webpackJsonp([1],[
	/* 0 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__(259)+__webpack_require__(274);
	
	/***/ }),
	/* 1 */,
	/* 2 */,
	/* 3 */,
	/* 4 */,
	/* 5 */,
	/* 6 */,
	/* 7 */,
	/* 8 */,
	/* 9 */,
	/* 10 */,
	/* 11 */,
	/* 12 */,
	/* 13 */,
	/* 14 */,
	/* 15 */,
	/* 16 */,
	/* 17 */,
	/* 18 */,
	/* 19 */,
	/* 20 */,
	/* 21 */,
	/* 22 */,
	/* 23 */,
	/* 24 */,
	/* 25 */,
	/* 26 */,
	/* 27 */,
	/* 28 */,
	/* 29 */,
	/* 30 */,
	/* 31 */,
	/* 32 */,
	/* 33 */,
	/* 34 */,
	/* 35 */,
	/* 36 */,
	/* 37 */,
	/* 38 */,
	/* 39 */,
	/* 40 */,
	/* 41 */,
	/* 42 */,
	/* 43 */,
	/* 44 */,
	/* 45 */,
	/* 46 */,
	/* 47 */,
	/* 48 */,
	/* 49 */,
	/* 50 */,
	/* 51 */,
	/* 52 */,
	/* 53 */,
	/* 54 */,
	/* 55 */,
	/* 56 */,
	/* 57 */,
	/* 58 */,
	/* 59 */,
	/* 60 */,
	/* 61 */,
	/* 62 */,
	/* 63 */,
	/* 64 */,
	/* 65 */,
	/* 66 */,
	/* 67 */,
	/* 68 */
	/***/ (function(module, exports) {
	
		// removed by extract-text-webpack-plugin
	
	/***/ }),
	/* 69 */,
	/* 70 */,
	/* 71 */,
	/* 72 */,
	/* 73 */,
	/* 74 */,
	/* 75 */,
	/* 76 */,
	/* 77 */,
	/* 78 */,
	/* 79 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__.p + "/static/img/a7Nznaj.gif";
	
	/***/ }),
	/* 80 */,
	/* 81 */,
	/* 82 */,
	/* 83 */,
	/* 84 */,
	/* 85 */,
	/* 86 */,
	/* 87 */,
	/* 88 */,
	/* 89 */,
	/* 90 */
	/***/ (function(module, exports) {
	
		// removed by extract-text-webpack-plugin
	
	/***/ }),
	/* 91 */,
	/* 92 */,
	/* 93 */,
	/* 94 */,
	/* 95 */,
	/* 96 */,
	/* 97 */,
	/* 98 */,
	/* 99 */,
	/* 100 */,
	/* 101 */,
	/* 102 */,
	/* 103 */,
	/* 104 */,
	/* 105 */,
	/* 106 */,
	/* 107 */,
	/* 108 */,
	/* 109 */,
	/* 110 */,
	/* 111 */,
	/* 112 */,
	/* 113 */,
	/* 114 */,
	/* 115 */,
	/* 116 */,
	/* 117 */,
	/* 118 */,
	/* 119 */,
	/* 120 */,
	/* 121 */,
	/* 122 */,
	/* 123 */,
	/* 124 */,
	/* 125 */,
	/* 126 */,
	/* 127 */,
	/* 128 */,
	/* 129 */,
	/* 130 */,
	/* 131 */,
	/* 132 */,
	/* 133 */,
	/* 134 */,
	/* 135 */,
	/* 136 */,
	/* 137 */,
	/* 138 */,
	/* 139 */,
	/* 140 */,
	/* 141 */,
	/* 142 */,
	/* 143 */,
	/* 144 */,
	/* 145 */,
	/* 146 */,
	/* 147 */,
	/* 148 */,
	/* 149 */,
	/* 150 */,
	/* 151 */,
	/* 152 */,
	/* 153 */,
	/* 154 */,
	/* 155 */,
	/* 156 */,
	/* 157 */,
	/* 158 */,
	/* 159 */,
	/* 160 */,
	/* 161 */,
	/* 162 */,
	/* 163 */,
	/* 164 */,
	/* 165 */,
	/* 166 */,
	/* 167 */,
	/* 168 */,
	/* 169 */,
	/* 170 */,
	/* 171 */,
	/* 172 */,
	/* 173 */,
	/* 174 */,
	/* 175 */,
	/* 176 */,
	/* 177 */,
	/* 178 */,
	/* 179 */,
	/* 180 */,
	/* 181 */,
	/* 182 */,
	/* 183 */,
	/* 184 */,
	/* 185 */,
	/* 186 */,
	/* 187 */,
	/* 188 */,
	/* 189 */,
	/* 190 */,
	/* 191 */,
	/* 192 */,
	/* 193 */,
	/* 194 */,
	/* 195 */,
	/* 196 */,
	/* 197 */,
	/* 198 */,
	/* 199 */,
	/* 200 */,
	/* 201 */,
	/* 202 */,
	/* 203 */,
	/* 204 */,
	/* 205 */,
	/* 206 */,
	/* 207 */,
	/* 208 */,
	/* 209 */,
	/* 210 */,
	/* 211 */,
	/* 212 */,
	/* 213 */,
	/* 214 */,
	/* 215 */,
	/* 216 */,
	/* 217 */,
	/* 218 */,
	/* 219 */,
	/* 220 */,
	/* 221 */,
	/* 222 */,
	/* 223 */,
	/* 224 */,
	/* 225 */,
	/* 226 */,
	/* 227 */,
	/* 228 */,
	/* 229 */,
	/* 230 */,
	/* 231 */,
	/* 232 */,
	/* 233 */,
	/* 234 */,
	/* 235 */,
	/* 236 */,
	/* 237 */,
	/* 238 */,
	/* 239 */,
	/* 240 */,
	/* 241 */,
	/* 242 */,
	/* 243 */,
	/* 244 */,
	/* 245 */,
	/* 246 */,
	/* 247 */,
	/* 248 */,
	/* 249 */,
	/* 250 */,
	/* 251 */,
	/* 252 */,
	/* 253 */,
	/* 254 */,
	/* 255 */,
	/* 256 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__.p + "/static/img/2z6meE1.gif";
	
	/***/ }),
	/* 257 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__.p + "/static/img/2KriyDK.png";
	
	/***/ }),
	/* 258 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__.p + "/static/img/xasUyAI.gif";
	
	/***/ }),
	/* 259 */
	/***/ (function(module, exports, __webpack_require__) {
	
		window.MMSource = {
			/*videoSwfPath:'/zh_CN/htmledition/v2/third_party/video-js-4.11.2/video-js.swf',*/
			copySwfPath:__webpack_require__(260),
			jplayerSwfPath:__webpack_require__(261)
		
		};
		
		__webpack_require__(262);
		__webpack_require__(266);
		__webpack_require__(267);
		__webpack_require__(268);
		__webpack_require__(269);
		__webpack_require__(270);
		__webpack_require__(271);
		__webpack_require__(272);
		__webpack_require__(273);
	
	/***/ }),
	/* 260 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__.p + "/static/res/1OM7Ut2.swf";
	
	/***/ }),
	/* 261 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__.p + "/static/res/GIqH2cS.swf";
	
	/***/ }),
	/* 262 */,
	/* 263 */,
	/* 264 */,
	/* 265 */,
	/* 266 */,
	/* 267 */,
	/* 268 */,
	/* 269 */,
	/* 270 */,
	/* 271 */,
	/* 272 */,
	/* 273 */,
	/* 274 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/**
		 * 临时IE console hack
		 */
		
		 
		// 这段 chack 代码可以废弃，线上环境过通过 uglifyjs 的drop_console 选项把 log输出干掉
		// (function() {
		//     var method;
		//     var noop = function () {};
		//     var methods = [
		//         'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
		//         'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
		//         'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
		//         'timeStamp', 'trace', 'warn'
		//     ];
		//     var length = methods.length;
		//     // 屏蔽log
		//     if(/mmdebug/.test(location.search) == false && location.href.indexOf('dev.web.weixin')<0){
		//         window.console = {};
		//     }
		//     var console = (window.console = window.console || {});
		//
		//     while (length--) {
		//         method = methods[length];
		//
		//         // Only stub undefined methods.
		//         if (!console[method]) {
		//             console[method] = noop;
		//         }
		//     }
		// }());
		/**
		 * fis的line语法:require(path)
		 * 作用：文件合并
		 */
		
		// import Controllers Module
		angular.module('Controllers', []);
		__webpack_require__(275);
		__webpack_require__(276);
		__webpack_require__(277);
		__webpack_require__(279);
		__webpack_require__(280);
		__webpack_require__(282);
		__webpack_require__(283);
		__webpack_require__(284);
		__webpack_require__(285);
		__webpack_require__(286);
		__webpack_require__(287);
		__webpack_require__(288);
		
		// import Services Module
		angular.module('Services',[]);
		__webpack_require__(289);
		__webpack_require__(290);
		__webpack_require__(291);
		__webpack_require__(292);
		__webpack_require__(293);
		__webpack_require__(294);
		__webpack_require__(295);
		__webpack_require__(296);
		__webpack_require__(297);
		__webpack_require__(298);
		__webpack_require__(299);
		__webpack_require__(300);
		__webpack_require__(301);
		__webpack_require__(302);
		__webpack_require__(303);
		__webpack_require__(304);
		__webpack_require__(305);
		__webpack_require__(307);
		__webpack_require__(308);
		__webpack_require__(309);
		__webpack_require__(310);
		
		// import Directives Module
		angular.module('Directives', []);
		__webpack_require__(311);
		__webpack_require__(312);
		__webpack_require__(313);
		__webpack_require__(314);
		__webpack_require__(315);
		__webpack_require__(316);
		__webpack_require__(317);
		__webpack_require__(318);
		__webpack_require__(319);
		__webpack_require__(320);
		/*require("./directives/videojsDirective.js");*/
		__webpack_require__(321);
		__webpack_require__(322);
		__webpack_require__(323);
		__webpack_require__(324);
		__webpack_require__(325);
		__webpack_require__(326);
		__webpack_require__(327);
		__webpack_require__(328);
		__webpack_require__(329);
		__webpack_require__(330);
		__webpack_require__(331);
		__webpack_require__(332);
		__webpack_require__(333);
		__webpack_require__(334);
		__webpack_require__(335);
		__webpack_require__(336);
		
		// import Filters
		angular.module('Filters', []);
		__webpack_require__(338);
		__webpack_require__(339);
		
		/**
		 * 程序入口，导入依赖模块
		 * 业务主逻辑：appController
		 */
		(function() {
			'use strict';
		
		angular.module('webwxApp', [
			'ui.router',
			'ngAnimate',
			'Services',
			'Controllers',
			'Directives',
			'Filters',
			'ngDialog',
			'jQueryScrollbar',
			'ngClipboard',
			'exceptionOverride'
			// 'perfect_scrollbar',
			//'ui.utils',
			//'ui.bootstrap'
		])
		.run(['$rootScope','$state','$stateParams',
			function ($rootScope,$state,$stateParams) {
				$rootScope.$state = $state;
				$rootScope.$stateParams = $stateParams;
			}
		])
			.factory('httpInterceptor', ['accountFactory', function (accountFactory) {
				return {
					'request': function(config) {
						if(!config.cache && config.url.indexOf('.html')<0){
							if(!config.params){
								config.params={};
							}
		
							config.params['pass_ticket']=accountFactory.getPassticket();
						}
		
						if(config.url.indexOf('.html')<0){
							var matchs = location.href.match(/(\?|&)lang=([^&#]+)/);
		
							if(matchs){
								var lang = matchs[2];
								if(!config.params){
									config.params={};
								}
								config.params['lang']= lang;
							}
		
						}
		
		
						return config;
					}
				}
			}])
		.config(['$sceProvider','$httpProvider', '$logProvider', '$stateProvider', '$urlRouterProvider','ngClipProvider',
			function($sceProvider, $httpProvider,$logProvider, $stateProvider, $urlRouterProvider,ngClipProvider) {
				// Completely disable SCE to support IE7.
				$sceProvider.enabled(false);
				$logProvider.debugEnabled(true);
		
				ngClipProvider.setPath(window.MMSource.copySwfPath);
				$httpProvider.interceptors.push('httpInterceptor');
		
				// var isCrossDomain = document.domain.indexOf('qq.com') < 0;
				//
				// if(!isCrossDomain){
				//     // set domain
				//     document.domain = 'qq.com';
				// }
				//
		
		
				var readItemCache;
		
				//$urlRouterProvider.when('', '/chat');
				//$urlRouterProvider.otherwise('');
				// config ui-router state
				$stateProvider.state("chat", {
					url: "",
					params: {userName:""},
					views: {
						"navView": {
						   // templateUrl: "navChat.html",
							controller: [
								'$stateParams',
								'chatFactory',
								'contactFactory',
								'stateManageService',
								'$rootScope',
								function($stateParams,chatFactory,contactFactory,stateManageService,$rootScope) {
									stateManageService.change('navChat:active',true);
									if($stateParams.userName){
										var user = contactFactory.getContact($stateParams.userName,'',true);
										if(!user){
											contactFactory.addBatchgetContact({
												UserName:$stateParams.userName,
												ChatRoomId:""
											},true).then(function(data){
												changeCurrentUser();
												console.log('addBatchgetContact now ok',data);
											},function(data){
												console.error('addBatchgetContact now err',data);
											});
										}else{
											changeCurrentUser();
										}
									}
									function changeCurrentUser(){
										var user = contactFactory.getContact($stateParams.userName,'',true);
										$rootScope.$broadcast('root:statechange');
										chatFactory.setCurrentUserName($stateParams.userName);
										chatFactory.addChatList([user||{'FromUserName':$stateParams.userName}]);
										$stateParams.userName = '';
									}
								}
							]
						},
						"contentView": {
							templateUrl: "contentChat.html",
							controller: "contentChatController"
						}
					}
				}).state("contact", {
					url: "",
					views: {
						"navView": {
							//templateUrl: "navContact.html",
							 controller: ['stateManageService',function(stateManageService){
								 stateManageService.change('navContact:active',true);
							 }]
						},
						"contentView": {
							templateUrl: "contentContact.html",
							controller: "contentContactController"
						}
					}
				}).state("read", {
					url: "",
					params: {readItem:""},
					views: {
						"navView":  {
							//templateUrl: "navContact.html",
							controller: ['stateManageService',function(stateManageService){
								stateManageService.change('navRead:active',true);
							}]
						},
						"contentView": {
							templateUrl: "contentRead.html",
							controller: ['$scope','$stateParams','subscribeMsgService', 'mmpop',function($scope,$stateParams,subscribeMsgService, mmpop){
								if($stateParams.readItem){
									readItemCache = $scope.readItem = $stateParams.readItem;
								}else{
									var firstSubscribe = subscribeMsgService.getSubscribeMsgs()[0];
									$scope.readItem = readItemCache || (firstSubscribe && firstSubscribe.MPArticleList[0]);
								}
		
								/**
								 * 左键菜单
								 */
								$scope.optionMenu = function () {
									mmpop.toggleOpen({
										templateUrl: "readMenu.html",
										//top:40,
										//left: 520,
										container:angular.element(document.querySelector('.read_list_header')),
										controller:'readMenuController',
										singletonId:'mmpop_reader_menu',
										className: "reader_menu"
									});
								};
							  /*  if(!isCrossDomain){
									// 往iframe注入script
									$("#reader").load(function () {
										var body = $(this).contents().find("body");
										var dom = body.find('#js_view_source');
										if (dom.length > 0){
											body.css({position: 'relative'});
											var view_source = $('<a href="javascript:;" onclick="var url = window.msg_source_url || window.location.href; var win = window.top.open(url, \'_blank\'); win.focus();" style="position: absolute; bottom: 20px; left: 15px; width: 4em; height: 25px; background: #FFFFFF;">阅读原文</a>');
											body.append(view_source);
										}
									});
								}*/
		
							}]
						}
					}
				});
			}]);
			angular.bootstrap(document, ['webwxApp']);
		})();
	
	/***/ }),
	/* 275 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		if(location.href.indexOf('dev.web')<0){
			angular.module('exceptionOverride', []).factory('$exceptionHandler', [function() {
				return function(exception, cause) {
					//exception.message += ' (caused by "' + cause + '")';
					window._errorHandler &&  window._errorHandler(exception);
					console.log(exception);
					throw exception;
				};
			}]);
		} else{
			angular.module('exceptionOverride', []);
		}
		
		/* Controllers */
		angular.module('Controllers')
		.controller('appController', [
			'$rootScope',
			'$scope',
			'$timeout',
			'$log',
			'$state',
			'$window',
			'ngDialog',
			'mmpop',
			'appFactory',
			'loginFactory',
			'contactFactory',
			'accountFactory',
			'chatFactory',
			'confFactory',
			'contextMenuFactory',
			'notificationFactory',
			'utilFactory',
				'reportService',
				'monitorService',
				'actionTrack',
				'surviveCheckService',
				'subscribeMsgService',
				'stateManageService',
			function($rootScope,$scope, $timeout,$log,$state,$window,
					 ngDialog, mmpop, appFactory, loginFactory,
					 contactFactory, accountFactory, chatFactory,
					 confFactory,contextMenuFactory, notificationFactory, utilFactory,reportService, monitorService, actionTrack,surviveCheckService,subscribeMsgService,stateManageService) {
		
				if (Math.floor(Math.random() * 100) == 1) {
					monitorService.report(monitorService.PV, 1);
				}
				// window.addEventListener('error', function() {
				//     monitorService.report(monitorService.EXCEPTION_COUNT, 1, 30000);
				// }, false);
		
				var appTiming = window._appTiming = {};
				$state.go('chat');
				$rootScope.CONF = confFactory;
		
				// export isUnLogin and CONF to scope
				$scope.isUnLogin = !window.MMCgi.isLogin;
				$scope.debug = true;
				$scope.isShowReader = /qq\.com/gi.test(location.href) && !confFactory.isClientVersion;
		
				var _rChatList = [];
		
				//缩放检测
				//$scope.isZoom = detectZoom.zoom() != 1;
				//console.log('是否缩放', $scope.isZoom);
		
				// if user is already login， then call pageInit directly
				if(window.MMCgi.isLogin){
					pageInit();
				}
		
			   // accountFactory.setPassticket(utilFactory.getCookie('webwx_data_ticket'));
		
		
				// listen event `newLoginPage`
				$scope.$on('newLoginPage',function (e,data) {
					console.log('newLoginPage',data);
					accountFactory.setSkey(data.SKey);
					accountFactory.setSid(data.Sid);
					accountFactory.setUin(data.Uin);
					accountFactory.setPassticket(data.Passticket);
					pageInit();
					updateAssociation(data.Uin);
				});
		
				var searchTimer,searchList;
				function _pickContact(){
					return contactFactory.pickContacts(['friend','chatroom'/*,brand*/],{
						chatroom:{
							keyword:$scope.keyword,
							isNewArray:true
						},
						friend:{
							keyword:$scope.keyword,
							isNewArray:true,
							isWithoutBrand:true,
							showFriendHeader:true
						}/*,
						 brand:{
						 keyword:$scope.keyword,
						 isNewArray:true
						 }*/
					},true).result;
				}
				$scope.search = function (e) {
					if(searchTimer){ $timeout.cancel(searchTimer); }
					searchTimer = $timeout(function(){
						if(!$scope.keyword){
							searchList && searchList.close();
							return;
						}
						searchList && searchList.close();
						searchList = mmpop.open({
							templateUrl:"searchList.html",
							//templateUrl:"searchList.html",
							controller: ['$rootScope', '$scope', '$state', function ($rootScope, scope, $state) {
								scope.$watch(function () {
									return contactFactory.contactChangeFlag;
								},function (newValue) {
									scope.allContacts.length = 0;
									scope.allContacts.push.apply(scope.allContacts,_pickContact()) ;
		
									/*{
									 text:_("59d29a3"),
									 type:'header'
									 }*/
									/*contactFactory.remoteSearch($scope.keyword).then(function(result){
										if(result.length > 0){
											scope.allContacts.push({
												text:_("59d29a3"),
												type:'header'
											})
											scope.allContacts.push.apply(scope.allContacts,result);
										}
		
									})*/
		
								});
								scope.clickUserCallback = function (contact) {
									if(!contact.UserName) return;
		
									$state.go('chat',{userName:contact.UserName});
									scope.closeThisMmPop();
									$rootScope.$broadcast('root:searchList:cleanKeyWord');
								};
							}],
							scope:{
								keyword: $scope.keyword,
								allContacts: _pickContact(), // searchListDirect需要用到
								heightCalc:function(item){
									if(item.type === 'header'){
										return 31;
									}else{
										return 60;
									}
								}
							},
							className: "recommendation",
							autoFoucs:false,
							container:angular.element(document.querySelector('#search_bar'))
						});
					}, 200);
				};
				$scope.searchKeydown = function(e){
					switch(e.keyCode){
						case confFactory.KEYCODE_ARROW_UP:
							searchList && searchList.isOpen() && $rootScope.$broadcast("root:searchList:keyArrowUp");
							e.preventDefault();
							e.stopPropagation();
							break;
						case confFactory.KEYCODE_ARROW_DOWN:
							searchList && searchList.isOpen() && $rootScope.$broadcast("root:searchList:keyArrowDown");
							e.preventDefault();
							e.stopPropagation();
							break;
						case confFactory.KEYCODE_ENTER:
							searchList && searchList.isOpen() && $rootScope.$broadcast("root:searchList:keyEnter");
							e.preventDefault();
							e.stopPropagation();
							break;
					}
				};
				$scope.$on('root:searchList:cleanKeyWord',function (e) {
					$scope.keyword = '';
				});
		
				// dialog垂直居中处理
				var dialog;
				function resetDialogPosition(){
					var el = dialog;
					if(!el) return;
					setTimeout(function(){
						var pt = (el[0].clientHeight - el.find('.ngdialog-content').height())/2;
						el.css('paddingTop',pt);
					},20);
				}
				$scope.$on('ngDialog.opened',function(e,el){
					stateManageService.change('dialog:open',true);
					dialog = el;
					resetDialogPosition();
					//console.log(e,el.find('.ngdialog-content').height());
				});
				$scope.$on('ngDialog.closed',function(e,el){
					stateManageService.change('dialog:open',false);
					dialog = null;
				});
				$(window).on('resize',function(e){
					resetDialogPosition();
					$scope.$broadcast('app:contextMenu:hide',e);
					$scope.$digest();
				});
				// end
		
		
				// `body` element click event, hide context menu
				$scope.appClick = function (e) {
					//console.log(e);
					$scope.$broadcast("app:contextMenu:hide",e);
				};
		
				var $body = $(document.body);
				var lastenter;
				$body.on('dragenter',function(e){
					var event  = e.originalEvent;
					lastenter = event.target;
					event.dataTransfer.dropEffect='none';
					$body.addClass('drop-enter');
					event.stopPropagation();
					event.preventDefault();
				})
				$body.on('dragleave',function(e){
					var event  = e.originalEvent;
					event.dataTransfer.dropEffect='none';
					if (lastenter === event.target) {
						$body.removeClass('drop-enter');
					}
					event.stopPropagation();
					event.preventDefault();
				})
				$body.on('dragover',function(e){
					var event  = e.originalEvent;
					event.dataTransfer.dropEffect='none';
					event.stopPropagation();
					event.preventDefault();
				})
				$body.on('drop',function(e){
					var event  = e.originalEvent;
					event.dataTransfer.dropEffect='none';
					event.stopPropagation();
					event.preventDefault();
				})
		
		
				// show context menu
				$scope.showContextMenu = function (e) {
					//contextMenuFactory.setContextMenuEvent(e);
					$scope.$broadcast("app:contextMenu:show",e);
				};
		
				// show system menu
				$scope.toggleSystemMenu = function (e) {
					mmpop.toggleOpen({
						templateUrl:"systemMenu.html",
						//templateUrl:"systemMenu.html",
						top:60,
						left:85,
						container:angular.element(document.querySelector('.panel')),
						controller:'systemMenuController',
						singletonId:'mmpop_system_menu',
						className: "system_menu"
					});
				};
		
				/**
				 * show contact profile
				 */
				$scope.showProfile = function (e) {
					if (!$scope.account){
						return;
					}
					var contact = $scope.account;
					var top = e.pageY + 25;
					var left = e.pageX + 6;
		
					mmpop.open({
						templateUrl:'profile_mini.html',
						//templateUrl:'profile_mini.html',
						className:'profile_mini_wrap scale-fade',
						top:top,
						left:left,
						blurClose:true,
						singletonId:'mmpop_profile',
						controller:["$scope",function (scope) {
							scope.contact = contact;
							scope.addUserContent = '';
							scope.isShowSendBox = false;
							scope.chat = function(userName){
								$state.go('chat',{userName:userName});
								scope.closeThisMmPop();
							};
						}]
					});
				};
		
				$scope.dblclickChat = function () {
					$scope.$broadcast("app:chat:dblclick");
				};
		
				$scope.requestPermission = function(){
					notificationFactory.requestPermission(function(){
						utilFactory.log('请求权限了...')
					});
				};
		
				// page init method
				function pageInit () {
					// set isLoaded and isUnLogin variable
					$scope.isLoaded = true;
					$scope.isUnLogin = false;
					reportService.report(reportService.ReportType.timing,{
						timing:{
							initStart:Date.now()
						}
					});
		
		
					// get data from server for the first time
					appFactory.init().then(function (data) {
						utilFactory.log('initData',data);
						if(data.BaseResponse && data.BaseResponse.Ret != "0"){
							console.log("BaseResponse.Ret",data.BaseResponse.Ret);
							if (!loginFactory.timeoutDetect(data.BaseResponse.Ret)) {
								ngDialog.openConfirm({
									className:'default ',
									templateUrl:'comfirmTips.html',
									controller:['$scope',function(scope){
										scope.title = _("02d9819");
										scope.content = _("0d2fc2c");
										reportService.report(reportService.ReportType.initError,{
											text:'程序初始化失败，点击确认刷新页面',
											code:data.BaseResponse.Ret,
											cookie:document.cookie
										});
										scope.callback = function () {
											//utilFactory.clearCookie();
											document.location.reload(true);
										};
									}]
								});
								// 上报初始化失败
								monitorService.report(monitorService.INIT_EXCEPTION_COUNT, 1);
							}
							return;
						}else{
						 /*   // 非白名单用户跳回旧版
							if(data.GrayScale != 1){
								window.onbeforeunload = null;
								document.location.href = location.protocol + '//' + location.host + '?lang=' + confFactory.LANG;
							}*/
						}
		
						// 记录登录时间
						accountFactory.setLoginTime(new Date().getTime());
		
						// set user information
						accountFactory.setUserInfo(data.User);
		
						// set sKey
						accountFactory.setSkey(data.SKey);
		
						// set syncKey
						accountFactory.setSyncKey(data.SyncKey);
		
						// add myself
						contactFactory.addContact(data.User);
		
						// add top 10 Contacts
						contactFactory.addContacts(data.ContactList);
		
						// add chat list
						//chatFactory.addChatList(data.ContactList);
						chatFactory.initChatList(data.ChatSet);
		
						//sync mobile chatList
						chatFactory.notifyMobile(accountFactory.getUserName(),confFactory.StatusNotifyCode_INITED);
		
						subscribeMsgService.init(data.MPSubscribeMsgList);
		
						$rootScope.$broadcast("root:pageInit:success");
						utilFactory.setCheckUrl(accountFactory);
						utilFactory.log('getUserInfo',accountFactory.getUserInfo());
		
						$scope.$broadcast("updateUser");
		
						reportService.report(reportService.ReportType.timing,{
							timing:{
								initEnd:Date.now()
							}
						});
		
		
		
						var trackTimeOut = data.ClickReportInterval || 1000 * 60 * 5;
						setTimeout(function reportTrack(){
							actionTrack.report();
							setTimeout(reportTrack,trackTimeOut);
						},trackTimeOut);
		
		
						// init all Contacts
						$timeout(function () {
							reportService.report(reportService.ReportType.timing,{
								timing:{
									initContactStart:Date.now()
								}
							});
		
							var count = 1;
							function next(seq){
								contactFactory.initContact(seq).then(function (data) {
									//console.log('initContact',data.MemberList.length);
									contactFactory.addContacts(data.MemberList);
		
									reportService.report(reportService.ReportType.timing,{
										timing:{
											initContactEnd:Date.now()
										},
										needSend:true
									});
		
									if(count <= 16 && data.Seq && data.Seq != 0){
										count++;
										next(data.Seq);
									}
								});
							}
		
							next(0);
						},0);
		
						$scope.account = contactFactory.getContact(accountFactory.getUserName());
						//drawChatBackgroundImage($scope.account.HeadImgUrl);
		
						checkMessage();
					});
		
		
					if (utilFactory.browser.chrome /*&& !MMDEV*/){
						window.onbeforeunload = function (e) {
							e = e || window.event;
							if (e){
								e.returnValue = '关闭浏览器聊天内容将会丢失。';
							}
		
							setTimeout(function() {
								// report session data
								console.time('report');
								var stayTime = new Date().getTime() - accountFactory.getLoginTime();
								reportService.report(reportService.ReportType.sessionData, {
									uin: accountFactory.getUin(),
									browser: navigator.userAgent,
									rmsg: accountFactory.getRMsgCount(),
									rconv: accountFactory.getRConvCount(),
									smsg: accountFactory.getSMsgCount(),
									sconv: accountFactory.getSConvCount(),
									lifetime: stayTime
								}, true);
							}, 0);
		
							return '关闭浏览器聊天内容将会丢失。';
						}
					}
				}
				surviveCheckService.callback(checkMessage);
				// start to polling data from server....
				var syncCheckTimer;
				var syncNeverStopTimer;
				function checkMessage () {
					if(!$scope.debug){
						return;
					}
					syncCheckTimer && $timeout.cancel(syncCheckTimer);
				   // syncNeverStopTimer && $timeout.cancel(syncNeverStopTimer);
					surviveCheckService.start(40000);
					syncCheckTimer = $timeout(function () {
					  /*  syncNeverStopTimer = setTimeout(function(){
							checkMessage ();
						},5000);*/
						appFactory.syncCheck()
							.then(function(result){
								surviveCheckService.start(5000);return result},
							function(e){ surviveCheckService.start(2000);return e;})
							.then(syncCheckHasChange,
							syncCheckNoChange);
					},confFactory.TIMEOUT_SYNC_CHECK);
				}
		
				//polling some data from server and then handle data, and start next polling...
		
				/**
				 * data contains :
				 * - 添加消息数`AddMsgCount`、消息内容`AddMsgList`
				 * - 修改联系人的列表的总数`ModContactCount`、修改联系人的列表`ModContactList`
				 * - 删除联系人的列表总数`DelContactCount`、删除联系人的列表`DelContactList`
				 * - 群成员信息变动总数`ModChatRoomMemberCount`、群成员信息变动`ModChatRoomMemberList`
				 * @param data
				 */
				function syncCheckHasChange (data) {
					utilFactory.log('syncCheckHasChange',data);
					try{
						accountFactory.setSyncKey(data.SyncKey);
						accountFactory.setSyncCheckKey(data.SyncCheckKey);
						//modify account info
						accountFactory.updateUserInfo(data.Profile,function () {
							//redraw account headImg
							//drawChatBackgroundImage(accountFactory.getUserInfo().HeadImgUrl);
						});
						//delete contacts
						angular.forEach(data.DelContactList,function (contact,index) {
							chatFactory.deleteChatList(contact.UserName);
							chatFactory.deleteChatMessage(contact.UserName);
							contactFactory.deleteContact(contact);
							if(chatFactory.getCurrentUserName()==contact.UserName){
								chatFactory.setCurrentUserName('');
							}
							console.log('DelContactList',data.DelContactList);
						});
						//modify contacts
						angular.forEach(data.ModContactList,function (contact,index) {
							contactFactory.addContact(contact);
							console.log('ModContactList',data.ModContactList);
						});
						//add message
						angular.forEach(data.AddMsgList,function (message,index) {
							chatFactory.messageProcess(message);
		
							// 如果发送者是自己，就不统计
		
							if (message.FromUserName == accountFactory.getUserName()) {
								return;
							}
		
							// 记录收消息数
							accountFactory.setRMsgCount(accountFactory.getRMsgCount() + 1);
		
							// 记录收会话数量
							var index = _rChatList.indexOf(message.FromUserName);
							if(index == -1) {
								accountFactory.setRConvCount(accountFactory.getRConvCount() + 1);
								_rChatList.push(message.FromUserName);
							}
						});
		
					}catch (e){
						e.other = {
							reason:'throw err when syncChackHasChange'
						};
						window._errorHandler &&  window._errorHandler(e);
					}finally{
						checkMessage();
					}
		
		
				}
		
				// polling no data from server and then start next polling...
				function syncCheckNoChange (data) {
					//console.log('syncCheckNoChange',data);
					checkMessage();
				}
		
				function drawChatBackgroundImage (headImgUrl) {
					// Change this value to adjust the amount of blur
					var BLUR_RADIUS = 100;
		
					var canvas = document.getElementById("heroCanvas");
					if(!canvas || !canvas.getContext) return;
		
					var canvasContext = canvas.getContext('2d');
					var image = new Image();
					image.src = headImgUrl;
		
					image.onload = function() {
						var w = canvas.width;
						var h = canvas.height;
						canvasContext.drawImage(image, 0, 0, w, h);
		
						// 灰度
						var pixels = canvasContext.getImageData(0, 0, w, h);
						for(var y = 0; y < pixels.height; y++){
							for (var x = 0; x < pixels.width; x++){
								var i = y * 4 * pixels.width + x * 4;
								var avg = (pixels.data[i] + pixels.data[i + 1] + pixels.data[i + 2]) / 3;
								pixels.data[i] = avg;
								pixels.data[i + 1] = avg;
								pixels.data[i + 2] = avg;
							}
						}
						canvasContext.putImageData(pixels, 0, 0, 0, 0, pixels.width, pixels.height);
		
						// 毛玻璃
						stackBlurCanvasRGBA('heroCanvas', 0, 0, w, h, BLUR_RADIUS);
		
						canvasContext.fillStyle = 'rgba(0, 0, 0, .35)';
						canvasContext.fillRect(0, 0, w, h);
					};
				}
		
				// 记录上次登录的uin，连续登录两次后，第三次启用关联登录
				function updateAssociation(uin){
					var lastUin = utilFactory.getCookie('last_wxuin') || '';
					var frequency = parseInt(utilFactory.getCookie('login_frequency') || 1);
					// 如果本次登录的用户和上次登录的不同，就重置关联登录条件的次数
					if(lastUin !== uin){
						frequency = 1;
					}
					else{
						frequency += 1;
					}
					console.log('updateAssociation: ', lastUin, frequency);
					utilFactory.setCookie('login_frequency', frequency, 2);
					utilFactory.setCookie('last_wxuin', uin, 2);
					utilFactory.getLocalStorage().setItem('userAvatar', window.userAvatar);
				}
		
				$scope.isIPad = utilFactory.isIPad;
				$scope.isMacOS = utilFactory.isMacOS;
				$scope.isWindows = utilFactory.isWindows;
		
				$scope.showDownloadEntry = $scope.isMacOS || $scope.isWindows;
		
				$scope.closeDownloadEntry = function () {
					$scope.showDownloadEntry = false;
					reportService.report(reportService.ReportType.click2CloseAd, {
						count: 1
					});
					new Image().src = "https://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportforweb?rid=69373&rkey=17&rvalue=1";
				};
				$scope.clickAndClose = function () {
					reportService.report(reportService.ReportType.clickAndCloseAd, {
						count: 1
					});
					new Image().src = "https://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportforweb?rid=69373&rkey=16&rvalue=1";
				};
		
			}
		]);
		})();
	
	
	/***/ }),
	/* 276 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Controllers */
		
		angular.module('Controllers')
		.controller('loginController', ['$scope', 'loginFactory','utilFactory','reportService', 'monitorService','confFactory', function($scope, loginFactory, utilFactory,reportService, monitorService,confFactory) {
			$('.lang .lang-item').click(function(e){
				$('script').remove();
				location.href = e.target.href;
				e.preventDefault();
			})
		
			if(window.MMCgi.isLogin){
				return;
			}
		
			$scope.isAssociationLogin = parseInt(utilFactory.getCookie('login_frequency') || 0) >= 2;
			$scope.isWaitingAsConfirm = false;
			$scope.isNeedRefresh = false;
			$scope.isRotateLoading = false;
			$scope.isBrokenNetwork = false; // 是否断网
			$scope.isClientVersion = confFactory.isClientVersion;
			var timeout;
		
			if($scope.isAssociationLogin){
				$scope.userAvatar = utilFactory.getLocalStorage().getItem('userAvatar');
			}
		
			$scope.showPrivacyTips = /wechat\.com/gi.test(location.host);
		
			/**
			 * 关联登录
			 */
			$scope.associationLogin = function (){
				var uin = utilFactory.getCookie('last_wxuin');
				$scope.isWaitingAsConfirm = true;
				loginFactory.associationLogin(uin).then(function (res){
					console.log('associationLogin reponse: ', res);
					$scope.uuid = res.uuid;
					doAssociationLogin();
				}, function (data){
					if(!data){
						$scope.isBrokenNetwork = true;
					}
					else{
						// 请求失败，转向二维码登录
						$scope.isAssociationLogin = false;
						utilFactory.setCookie('login_frequency', 0, 2);
						doQrcodeLogin();
						// 上报关联登录失败次数
						monitorService.report(monitorService.ASSOCIATION_AUTH_FAIL_COUNT, 1);
					}
				});
				timeout && clearTimeout(timeout);
				// 上报关联登录次数
				monitorService.report(monitorService.ASSOCIATION_AUTH_COUNT, 1);
			};
		
			/**
			 * 二维码登录
			 */
			$scope.qrcodeLogin = function (){
				// 防止连续点
				if(!$scope.isAssociationLogin){
					return;
				}
				$scope.isAssociationLogin = false;
				utilFactory.setCookie('login_frequency', 0, 2);
		
				// 终止轮询
				if(window.checkLoginPromise){
					window.checkLoginPromise.abort();
					window.checkLoginPromise = null;
				}
		
				doQrcodeLogin();
			};
		
			/**
			 * refreshQrcode
			 */
			$scope.refreshQrcode = function (){
				$scope.isRotateLoading = true;
				setTimeout(function(){
					doQrcodeLogin();
					$scope.isRotateLoading = false;
					$scope.isNeedRefresh = false;
				}, 1200);
			};
		
			$scope.reloadQrcode = function (){
				doQrcodeLogin();
				$scope.isBrokenNetwork = false;
			};
		
		
		
			$scope.qrcodeException = function () {
				monitorService.report(monitorService.QRCODE_EXCEPTION_COUNT, 1);
			};
		
			/**
			 * polling
			 * @param data
			 */
			function checkLoginHandler (data) {
				/**
				 * code：
				 *      200: 成功
				 *      201：扫描成功，但未点确认
				 *      408：未扫描
				 *      400：未知
				 *      500： login poll srv exception
				 *
				 */
				switch(data.code){
					case 200:
						loginFactory.newLoginPage(data.redirect_uri).then(function (msg) {
							var ret = msg.match(/<ret>(.*)<\/ret>/),
								code = msg.match(/<script>(.*)<\/script>/),
								skey=msg.match(/<skey>(.*)<\/skey>/),
								wxsid=msg.match(/<wxsid>(.*)<\/wxsid>/),
								wxuin=msg.match(/<wxuin>(.*)<\/wxuin>/),
								passticket=msg.match(/<pass_ticket>(.*)<\/pass_ticket>/),
								message=msg.match(/<message>(.*)<\/message>/),
								redirecturl=msg.match(/<redirecturl>(.*)<\/redirecturl>/);
		
		
		
		
							if(redirecturl){
								window.location.href = redirecturl[1];
								return;
							}
		
							if(ret && (ret[1] != '0')){
								alert((message && message[1])|| '登陆失败');
								monitorService.report(monitorService.AUTH_FAIL_COUNT, 1);
								location.reload();
								return;
							}
		
		
							$scope.$emit('newLoginPage',{
								Ret:ret && ret[1],
								SKey:skey && skey[1],
								Sid:wxsid && wxsid[1],
								Uin:wxuin && wxuin[1],
								Passticket:passticket && passticket[1],
								Code:code
							});
							if(!utilFactory.getCookie('webwx_data_ticket')){
								reportService.report(reportService.ReportType.cookieError,{
									text:'webwx_data_ticket 票据丢失',
									cookie:document.cookie
								});
							}
		
		
						});
						break;
					case 201:
						$scope.isScan = true;
						reportService.report(reportService.ReportType.timing,{
							timing:{
								scan:Date.now()
							}
						});
						loginFactory.checkLogin($scope.uuid).then(checkLoginHandler, function (data){
							if(!data && window.checkLoginPromise){
								$scope.isBrokenNetwork = true;
							}
						});
						break;
					case 408:
						loginFactory.checkLogin($scope.uuid).then(checkLoginHandler, function (data){
							if(!data && window.checkLoginPromise){
								$scope.isBrokenNetwork = true;
							}
						});
						break;
					case 400:
					case 500:
					case 0:
						// 这里要累计次数
						var refreshTimes = utilFactory.getCookie('refreshTimes') || 0;
						if(refreshTimes < 5){
							refreshTimes++;
							utilFactory.setCookie('refreshTimes', refreshTimes, 0.5);
							document.location.reload();
						}
						else{
							$scope.isNeedRefresh = true;
						}
						break;
					case 202: // 点击取消
						// 1. 关联登录，等待确认，取消
						// 2. 扫码之后，等待确认，取消
						$scope.isScan = false;
						$scope.isAssociationLogin = false;
						utilFactory.setCookie('login_frequency', 0, 2);
		
						// 终止轮询
						if(window.checkLoginPromise){
							window.checkLoginPromise.abort();
							window.checkLoginPromise = null;
						}
		
						doQrcodeLogin();
						break;
					default:
					//todo
				}
				$scope.code = data.code;
				$scope.userAvatar = data.userAvatar;
				utilFactory.log('get code',data.code);
			}
		
			/**
			 * 启动二维码登录
			 */
			function doQrcodeLogin() {
				loginFactory.getUUID().then(function (uuid) {
					utilFactory.log('login',uuid);
					$scope.uuid = uuid;
					$scope.qrcodeUrl = 'https://login.weixin.qq.com/qrcode/'+ uuid;
					$scope.code = 0;
					$scope.isScan = false;
					$scope.isIPad = utilFactory.isIPad;
					$scope.isMacOS = utilFactory.isMacOS;
					$scope.isWindows = utilFactory.isWindows;
					$scope.lang = utilFactory.queryParser().lang || 'zh_CN';
		
					var qrcodeLoaded = false;
					reportService.report(reportService.ReportType.timing,{
						timing:{
							qrcodeStart:Date.now()
						}
					});
					setTimeout(function(){
						if(!qrcodeLoaded){
							reportService.report(reportService.ReportType.picError,{
								text:'qrcode can not load',
								src:$scope.qrcodeUrl
							});
						}
					},3000);
					$scope.qrcodeLoad = function(){
						qrcodeLoaded = true;
						reportService.report(reportService.ReportType.timing,{
							timing:{
								qrcodeEnd:Date.now()
							}
						});
					};
					loginFactory.checkLogin(uuid,1).then(checkLoginHandler, function (data){
						if(!data && window.checkLoginPromise){
							$scope.isBrokenNetwork = true;
						}else{
							$scope.isBrokenNetwork = false;
						}
					});
				}, function (code){
					console.log('get uuid error');
					if(!code){
						$scope.isBrokenNetwork = true;
					}else{
						$scope.isBrokenNetwork = false;
					}
				});
			}
		
			/**
			 * 启动关联登录
			 */
			function doAssociationLogin(){
				loginFactory.checkLogin($scope.uuid, 1).then(checkLoginHandler, function (data){
					if(!data && window.checkLoginPromise){
						$scope.isBrokenNetwork = true;
					}
				});
			}
		
			// 如果没有登录，并且是二维码登录
			if(!window.MMCgi.isLogin && !$scope.isAssociationLogin){
				doQrcodeLogin();
			}
			else{
				timeout = setTimeout(function (){
					$scope.qrcodeLogin();
				}, 5 * 60 * 1000);
			}
		}]);
		})();
	
	
	/***/ }),
	/* 277 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function(){
			'use strict';
		
			/* Controllers */
		
			angular.module('Controllers')
				.controller('contentChatController', [
					'$scope',
					'$timeout',
					'$state',
					'$log',
					'$document',
					'$compile',
					'chatFactory',
					'accountFactory',
					'contactFactory',
					'appFactory',
					'confFactory',
					'utilFactory',
					'chatroomFactory',
					'mmpop',
					'ngDialog',
					'preview',
					'reportService',
					'mmHttp',
					'emojiFactory',
					function($scope, $timeout,$state,$log,$document,$compile,
							 chatFactory, accountFactory, contactFactory,
							 appFactory, confFactory, utilFactory,chatroomFactory,
							 mmpop, ngDialog, imagePreview, reportService, mmHttp,emojiFactory) {
						var chatBd = $document.find('#chatArea .scrollbar-dynamic')[0];
						$scope.delState = false;
						$scope.chatContent = [];
						$scope.isShowChatRoomMembers = false;
		
						$document.find('#chatArea').on('drop',function(e){
							var result = chatFactory.setSendFileUsername(chatFactory.getCurrentUserName());
							if(!result){
								alert(_("599d8df"))
								e.preventDefault();
								e.stopPropagation();
								e.stopImmediatePropagation()
								return false
							}
						})
		
						$scope.$on('message:add:success',function(e,msg){
		
							//
							if(msg.MMPeerUserName !== chatFactory.getCurrentUserName()){
								if(!msg._h){
									$scope.heightCalc(msg,function(height){
										msg._h = height;
									})
								}
							}
						});
		
						$scope.$watch(function () {
							//console.log(chatFactory.getCurrentUserName());
							return chatFactory.getCurrentUserName();
						}, function (newValue) {
							//if (newValue){
		
							updateChatContent(newValue);
							$scope.newMsg = null;
							$scope.isScrollToUnread = false;
							setTimeout(function(){
								chatBd.scrollTop = 999999;
								$scope.autoScrollFlag = true;
								setTimeout(function(){
									$scope.autoScrollFlag = false;
								},200)
							},10)
							//}
						});
		
						$scope.$on('root:cleanMsg',function (e,userName) {
							//console.log(e,userName);
							chatFactory.cleanChatMessage(userName);
							chatFactory.getChatList();
		
							if(userName == chatFactory.getCurrentUserName()){
								$scope.imagesMessagesList = [];
							}
						});
		
						$scope.$on("root:profile",function (e,obj) {
							$scope.showProfile(obj.event,obj.userName,obj.isAdd);
						});
		
						$scope.$on('root:msgSend:success',function(e,msg){
							if(msg.MsgType == confFactory.MSGTYPE_IMAGE) $scope.imageInit(msg);
		
							if(msg.ToUserName != $scope.currentUser) return;
							for (var i = 0, len = $scope.chatContent.length; i < len; ++i) {
								var contentMsg = $scope.chatContent[i];
								if(contentMsg.MsgId == msg.MsgId){
									switch(msg.AppMsgType){
										case confFactory.APPMSGTYPE_ATTACH:
											contentMsg.MMAppMsgDownloadUrl = contentMsg.MMAppMsgDownloadUrl.replace("#MediaId#", msg.MediaId).replace("mediaid=undefined", "mediaid="+msg.MediaId).replace('encryfilename=undefined', 'encryfilename=' + (msg.EncryFileName || encodeURIComponent(message.FileName)));
											break;
									}
									if(!$scope.$$phase) $scope.$digest();
									return;
								}
							}
						});
		
						$scope.$on('root:mmpop:closed', function (e, id) {
							if (id == 'mmpop_chatroom_members'){
								$scope.isShowChatRoomMembers = false;
								$scope.$digest();
							}
						});
		
						function updateChatContent (userName) {
							var currentContact = $scope.currentContact = contactFactory.getContact(userName);
							if(currentContact){
							  $scope.unreadMessageCount = currentContact.unreadCount;
							  currentContact.unreadCount = 0;
							}
		
							//console.log('updateChatContent',$scope.currentContact);
		
		
							/*
							* 用于识别 chatcontent 变更是不是切换会话引起的
							* */
							$scope.isChangeUserFlag = true;
							$scope.currentUser = userName;
							//$scope.currentUserNickName = $scope.currentContact.NickName;
							$scope.chatContent = chatFactory.getChatMessage(userName,true);
		
							$scope.unreadMessage =  $scope.chatContent[$scope.chatContent.length - $scope.unreadMessageCount];
							// 在message.html里进行imagesMessagesList.push(message.MsgId)操作
							$scope.imagesMessagesList=[];
							$scope.messagesAnimate = false;
							$timeout(function () {
								$scope.messagesAnimate = true;
							},200);
		
							if(currentContact){
								// 硬编码不能创建群聊的联系人，后续后端会配合改进
								var hardCodeStr = "newsapp,fmessage,filehelper,weibo,qqmail,fmessage,tmessage,qmessage,qqsync,floatbottle,lbsapp,shakeapp,medianote,qqfriend,readerapp,blogapp,facebookapp,masssendapp,meishiapp,feedsapp,voip,blogappweixin,weixin,brandsessionholder,weixinreminder,wxid_novlwrv3lqwv11,gh_22b87fa7cb3c,officialaccounts,notification_messages,wxid_novlwrv3lqwv11,gh_22b87fa7cb3c,wxitil,userexperience_alarm,notification_messages";
								currentContact.MMCanCreateChatroom = hardCodeStr.indexOf(currentContact.UserName)<0;
							}
		
						}
		
						$scope.getMsgImg = function (msgId,type,msg) {
							if(msg && (typeof msg.MMStatus != 'undefined') && msg.MMStatus!=confFactory.MSG_SEND_STATUS_SUCC){
								return undefined;
							}
		
							return confFactory.API_webwxgetmsgimg + '?'+'&MsgID='+ msgId +'&skey=' + encodeURIComponent(accountFactory.getSkey()) + (type?('&type='+type):'');
						}
						$scope.getMsgVideo = function (msgId) {
							return confFactory.API_webwxgetvideo + '?msgid='+ msgId +'&skey=' + encodeURIComponent(accountFactory.getSkey());
						}
		
						$scope.messageHandle = function(message){
							if(message.MMRecall){
								// todo: 其实不需要每次都执行，初次撤回处理的时候已经把大图取消掉了，之后更新消息的时候已经没必要处理（来新消息之类的所有消息都会重新渲染）
								removeImagePreview(message);
							}
						}
						function removeImagePreview(message){
							var imageList = $scope.imagesMessagesList;
							for(var i = 0;i< imageList.length;i++){
								if(imageList[i].msg.MsgId == message.MsgId){
									imageList.splice(i,1);
									break;
								}
							}
		
						}
		
						$scope.getUserContact = function (actualSender,FromUserName) {
							if(!actualSender && !FromUserName) return;
							if(FromUserName && actualSender != FromUserName){
								return contactFactory.getContact(actualSender,FromUserName);
							}else{
								return contactFactory.getContact(actualSender);
							}
						}
						$scope.appMsgClick = function (e,str) {
							if(str){
								alert(str);
								e.preventDefault();
							}
						};
						$scope.showVideo = function(msgId){
							var dialog = ngDialog.open({
								className:'default microvideo_preview_dialog',
								template:'<div jplayer-directive\
										id="jplayer-dialog-{{MsgId}}"\
										class="jp-jplayer microvideo"\
										src="{{getMsgVideo(MsgId)}}"\
										timeout="10"\
										ng-class="{loaded:loaded}"\
										poster="{{getMsgImg(MsgId,\'slave\')}}" autoplay loop></div>',
								plain:true,
								controller:['$scope',function(scope){
									scope.MsgId = msgId;
									scope.getMsgVideo = $scope.getMsgVideo;
									scope.getMsgImg = $scope.getMsgImg;
									scope.width = 800;
									scope.height = 600;
								}]
							});
						};
						$scope.showMicroVideo = function(msgId){
							var dialog = ngDialog.open({
								className:'default microvideo_preview_dialog',
								template:'<div jplayer-directive\
										id="jplayer-dialog-{{MsgId}}"\
										class="jp-jplayer microvideo"\
										src="{{getMsgVideo(MsgId)}}"\
										timeout="10"\
										ng-class="{loaded:loaded}"\
										poster="{{getMsgImg(MsgId,\'slave\')}}" autoplay loop></div>',
								plain:true,
								controller:['$scope',function(scope){
									scope.MsgId = msgId;
									scope.getMsgVideo = $scope.getMsgVideo;
									scope.getMsgImg = $scope.getMsgImg;
									scope.width = 800;
									scope.height = 600;
								}]
							});
		
						};
		
						$scope.scrollToTopUnread = function(){
						   /*
						   * 滚到未读消息
						   * */
						   if($scope.unreadMessage){
							   $scope.newMsg = $scope.unreadMessage;
							   $scope.isScrollToUnread = true;
							   $scope.unreadMessageCount = 0;
							   chatBd.scrollTop = $scope.unreadMessage._offsetTop;
						   }
		
						};
		
						$scope.scrollToBottomUnread = function(){
							if($scope.bottomUnreadIndex && $scope.bottomUnreadCount){
								var bottomUnreadMsg = $scope.chatContent[$scope.bottomUnreadIndex];
								if(bottomUnreadMsg){
									$scope.newMsg = bottomUnreadMsg;
									bottomUnreadMsg._h = 0;
									$scope.isScrollToUnread = true;
									$scope.bottomUnreadIndex = 0;
									clearBottomUnread();
									chatBd.scrollTop = bottomUnreadMsg._offsetTop;
									var cancel = $scope.$on('mmRepeat:reCalc',function() {
										chatBd.scrollTop = bottomUnreadMsg._offsetTop;
										cancel();
									});
		
								}
		
		
							}
		
		
						};
		
		
		
						var topUnreadTimer = null;
		
						$scope.$on('onScroll',function(e,scrollData){
							var scrollDataY = scrollData.y;
							if($scope.currentContact){
							  if(scrollDataY.maxScroll - scrollDataY.scroll > 260){
								if(!$scope.currentContact._notActive){
								  $scope.bottomUnreadIndex = $scope.chatContent.length;
								  $scope.currentContact._notActive= true;
								  $scope.$digest();
								}
							  }else{
								clearBottomUnread();
								$scope.currentContact._notActive= false;
								$scope.$digest();
							  }
							}
		
		
		
		
							if($scope.bottomUnreadIndex){
								var firstUnreadMsg = $scope.chatContent[$scope.bottomUnreadIndex];
								if(firstUnreadMsg){
									if(firstUnreadMsg._offsetTop < scrollDataY.scroll + scrollDataY.visible){
										clearBottomUnread();
										if(scrollDataY.maxScroll - scrollDataY.scroll > 260){
											$scope.bottomUnreadIndex = $scope.chatContent.length;
										}
									}
								}else{
									clearBottomUnread();
								}
							}
		
		
							clearTimeout(topUnreadTimer);
							topUnreadTimer = setTimeout(function(){
								if(!$scope.autoScrollFlag){
									if($scope.unreadMessage && $scope.unreadMessage._offsetTop >= scrollDataY.scroll){
										$scope.unreadMessageCount = 0;
										/*      $scope.unreadMessage =  null;*/
										$scope.$digest();
									}
								}
							},100);
		
						});
		
						$scope.previewImg = function(msg){
							var image,index;
							for(var i  = 0;i<$scope.imagesMessagesList.length;i++){
								image = $scope.imagesMessagesList[i];
								if(image.msg == msg){
									index = i;
									break;
								}
							}
		
		
							var status = msg.MMStatus;
							if(status !== undefined && status != confFactory.MSG_SEND_STATUS_SUCC) return;
							imagePreview.open({imageList:$scope.imagesMessagesList,current:index});
						};
						$scope.resendMsg = function(message){
							chatFactory.sendMessage(message);
						};
		
						$scope.imageInit = function(msg,previewUrl){
							// 由于 ng-repeat 的原因，此 init 会被多次调用，且在 root:msgSend:success 事件发生时也会调用，用于处理本人发送的图片延迟生效的问题
							var imageList= $scope.imagesMessagesList,imageItem,exist = false,msgImgUrl,index;
							// 如果 imageList 中已经有了该 msg，就把产生的新图片地址给他
		
		
							var msgImgUrl = $scope.getMsgImg(msg.MsgId);
							for(var i = 0;i <  imageList.length;i++){
								imageItem = imageList[i];
								if(imageItem.msg === msg){
									exist = true;
									imageItem.url = msgImgUrl;
									index = i;
									break;
								}
							}
		
		
		
							if(!exist) {
								var imagePreviewItem ;
								if(typeof msg.MMStatus === 'undefined' || msg.MMStatus==confFactory.MSG_SEND_STATUS_SUCC){
		
									imagePreviewItem = {url:msgImgUrl,msg:msg,preview:previewUrl};
		
								}else{
									//占位
									imagePreviewItem = {msg:msg,preview:previewUrl};
								}
		
								index = insertImagePreview(imageList,imagePreviewItem);
		
							}
		
						  /*  if(typeof  index === 'undefined'){
								index = imageList.length - 1;
							}*/
		
		
							return index;
						};
		
						function insertImagePreview(list,item){
							var current,i;
							for(i = 0; i<= list.length;i++){
								current = list[i];
								if(current){
									if(item.msg._index < current.msg._index){
										list.splice(i,1,item,current);
										break;
									}
								}else{
									list.push(item);
									break;
								}
							}
							return i;
						}
		
						/**
						 * show chat room members dialog
						 */
						$scope.showChatRoomMembers = function (e) {
							mmpop.toggleOpen({
								templateUrl: 'chatRoomMember.html',
								//templateUrl: 'chatRoomMember.html',
								scope:$scope,
								container:angular.element(document.getElementById('chatRoomMembersWrap')),
								className:'members_wrp slide-down',
								singletonId:'mmpop_chatroom_members',
								stopPropagation:false,
								controller:['$scope',function (scope) {
									$timeout(function (argument) {
										scope.currentContact = $scope.currentContact;
										scope.accountUserName = accountFactory.getUserName();
									},100);
									/**
									 * 添加群成员
									 */
									scope.addCharRoomMember = function () {
										var filterContacts = {};
										angular.forEach(scope.currentContact.MemberList,function (contact) {
											filterContacts[contact.UserName] = contact;
										});
										chatroomFactory.setCurrentContact(scope.currentContact);
										chatroomFactory.setFilterContacts(filterContacts);
										ngDialog.open({
											templateUrl: "createChatroom.html",
											controller: "createChatroomController",
											className: "default add_chatroom",
											data:{
												isAdd:true
											}
										});
										scope.closeThisMmPop();
									};
									/**
									 * 创建群聊
									 */
									scope.createChatroom = function () {
		
										ngDialog.open({
											templateUrl: "createChatroom.html",
											controller: "createChatroomController",
											className:"default create_chatroom_dlg",
											data:{
												isCreate:true,
												initSelectedContacts:[scope.currentContact]
											}
										});
										scope.closeThisMmPop();
									};
								}]
							});
							$scope.isShowChatRoomMembers = true;
							console.log($scope.isShowChatRoomMembers);
							e.preventDefault();
						};
		
						/**
						 * show contact profile
						 */
						$scope.showProfile = function (e,userName,isAdd) {
							var contact;
							if(userName){
								contact = contactFactory.getContact(userName,$scope.currentContact.UserName);
							}else{
								contact = $scope.currentContact;
							}
							var winEl = angular.element(window),
								w = 230,
								h = 360,
								winw = winEl.width(),
								winh = winEl.height(),
								top = e.pageY,
								left = e.pageX;
		
							if(winw - e.pageX < w){
								left = e.pageX - w;
							}
							if(winh - e.pageY < h){
								top = e.pageY - h;
							}
							mmpop.open({
								templateUrl: 'profile_mini.html',
								className:'profile_mini_wrap scale-fade',
								top:top,
								left:left,
								blurClose:true,
								singletonId:'mmpop_profile',
								controller:["$scope",function (scope) {
									if(contact.VerifyFlag){
										scope.isOfficialUser = true;
									}
		
									scope.contact = contact;
									scope.MMDefaultRemark = _("8d521cc");
									scope.addUserContent = _("5a97440") + emojiFactory.formatHTMLToSend(accountFactory.getUserInfo().NickName);
									scope.isShowSendBox = isAdd || false;
		
									/**
									 * 发起会话
									 * @param userName
									 */
									scope.chat = function(userName){
										$state.go('chat',{userName:userName});
										scope.closeThisMmPop();
									};
		
									/**
									 * 通过好友认证
									 */
									scope.verifyUser = function (e) {
										contactFactory.verifyUser({
											UserName:contact.UserName,
											Opcode:confFactory.VERIFYUSER_OPCODE_VERIFYOK,
											Scene:confFactory.ADDSCENE_PF_WEB,
											Ticket:contact.Ticket
										}).then(function (data) {
											scope.closeThisMmPop();
										},function (data) {
											scope.closeThisMmPop();
											alert('verify user error.');
										});
										/*e.preventDefault();
										 e.stopPropagation();*/
									};
		
									/**
									 * 修改备注名
									 */
									scope.editRemarkName = function(){
										if(scope.MMDefaultRemark == _("8d521cc")){
											scope.MMDefaultRemark = '';
										}
									};
									scope.text = emojiFactory.transformSpanToImg(scope.contact.RemarkName || "");
									scope.save = function(e){
										var textNode = $('.profile_mini_wrap .J_Text');
										var text = textNode.text();
										var len = text.length;
										if (e && [8, 37, 39, 46, 13].indexOf(e.keyCode) === -1 && len > 13){
											e.preventDefault();
											return;
										}
		
										if(!e||e.keyCode==13){
											if (text.length > 17){
												text = text.substring(0, 18);
											}
											scope.editing  = false;
											scope.contact.RemarkName = text;
											mmHttp({
												method:"POST",
												url:confFactory.API_webwxoplog,
												data:angular.extend({
													UserName:scope.contact.UserName,
													CmdId:confFactory.oplogCmdId.MODREMARKNAME,
													RemarkName:emojiFactory.formatHTMLToSend(text)
												}, accountFactory.getBaseRequest()),
												MMRetry:{
													count:3,
													timeout:10000,
													serial:true
												}
											}).success(function(data){
												// todo: 弱提示
												scope.MMDefaultRemark = _("8d521cc");
											}).error(function(data){
		
											});
											// 失去焦点
											$('<div contenteditable="true"></div>').appendTo('body').focus().remove();
										}
		
									};
		
									/**
									 * 请求添加到通讯录
									 */
									scope.addUser = function (e,content) {
										contactFactory.verifyUser({
											UserName:contact.UserName,
											Opcode:confFactory.VERIFYUSER_OPCODE_SENDREQUEST,
											Scene:confFactory.ADDSCENE_PF_WEB,
											Ticket:contact.Ticket,
											VerifyContent:content||''
										}).then(function (data) {
											scope.closeThisMmPop();
										},function (data) {
											scope.closeThisMmPop();
											//alert('add user error.');
											ngDialog.openConfirm({
												className:'default ',
												templateUrl: 'comfirmTips.html',
												controller:['$scope',function(scope){
													scope.title = _("02d9819");
													scope.content = data.BaseResponse.ErrMsg || _("f45a3d8");
													scope.callback = function () {
														scope.closeThisDialog();
													};
												}]
											});
										});
										/*e.preventDefault();
										 e.stopPropagation();*/
									};
								}]
							});
						};
		
						$scope.removeMemberFromChatroom = function (userName,delMember) {
							chatroomFactory.delMember(userName,delMember);
							mmpop.close('mmpop_chatroom_members');
						};
		
						var _endedFunc = function(){
								if(!window.MMplayingMsg) return;
		
								window.MMplayingMsg.MMPlaying = false;
								window.MMplayingMsg = null;
								if(!$scope.$$phase) $scope.$digest();
							};
						$scope.playVoice = function (message) {
							__webpack_require__.e/* nsure */(2, function (require) {
								var jplayer = __webpack_require__(278);
								var voicePlayer = jQuery('#voiceMsgPlayer');
								if(window.MMplayingMsg){
									if(message.MsgId == window.MMplayingMsg.MsgId && message.MMPlaying){ // 如果是点击一条正在播放的消息，则停止
										voicePlayer.jPlayer("stop");
										return;
									}
									_endedFunc();
								}
		
								var url = confFactory.API_webwxgetvoice + '?msgid='+message.MsgId+'&skey='+accountFactory.getSkey();
		
								if(message.MMVoiceUnRead) message.MMVoiceUnRead = false;
		
								message.MMPlaying = true; // 语音播放标志位(显示动画)
								voicePlayer.jPlayer({
									ready: function () {},
									timeupdate: function(event) {},
									play: function(event) {},
									pause: _endedFunc,
									ended: _endedFunc,
									swfPath: window.MMSource.jplayerSwfPath,
									solution: 'html, flash',
									supplied: "mp3",
									wmode: "window"
								});
		
								voicePlayer.jPlayer("stop");
								window.MMplayingMsg = message;
								voicePlayer.jPlayer("setMedia", {mp3:url});
								voicePlayer.jPlayer("play");
							});
						};
		
						var shouldScroll = false;
		
						$scope.$on('mmRepeat:change',function(){
							if(shouldScroll){
							   chatBd.scrollTop =99999;//chatBd.scrollHeight;
							}
						});
		
		
						var scrollTimer ,shouldCalc=true;
						$scope.$watchCollection('chatContent',function(list){
							if(list.length > 0 &&list[list.length-1].FromUserName === accountFactory.getUserName()){
								shouldScroll = true;
							}else{
		
								if( $scope.isChangeUserFlag ){
									$scope.isChangeUserFlag = false;
									clearBottomUnread();
								}else {
									if($scope.bottomUnreadIndex && $scope.currentContact){
										$scope.bottomUnreadCount = chatFactory.getUnreadMsgsCount($scope.currentContact.UserName);
									}else{
										clearBottomUnread();
									}
								}
		
		
		
		
								/*
								 * 内容一旦改变，在 mmrepeat 改变高度之前，确定现在是否处于应该滚动的情况（shouldScroll）,并且连环发送的时候，不会改变 shouldScroll 的结果。
								 * 此时我们做出了一个假设 ， 就是 “用户在间隔低于100ms的输入的时候，不可能去主动滚动聊天区域”
								 *
								 * 注意：由于聊天区域的高度改变等都是异步的，时序难以确定，所以一般的 “滚到底部” 的手法难以生效，慎重改动此区域代码
								 * */
								scrollTimer && clearTimeout(scrollTimer);
								scrollTimer = setTimeout(function(){
									shouldCalc = true;
								},100);
		
								if(!shouldCalc) {
									return ;
								}
		
								shouldScroll = chatBd.scrollTop + chatBd.clientHeight + 260 >= chatBd.scrollHeight;
								shouldCalc = false;
							}
		
		
						})
		
						$scope.heightCalc = function(item,cb){
		
							var angularDomEl = '<div message-directive ></div>';
							var newScope = $scope.$new();
							newScope.imageInit = function(){};
							newScope.message = item;
							var domEl = $compile(angularDomEl)(newScope);
		
		
							$('#prerender').append(domEl);
							(function(newScope,domEl,item,cb){
								setTimeout(function(){
									if(item.MsgType == confFactory.MSGTYPE_EMOTICON ||item.MsgType ==  confFactory.MSGTYPE_IMAGE || item.MsgType == confFactory.MSGTYPE_VIDEO){
		
										newScope.$digest();
		
										var img = domEl.find('.content .msg-img');
										var imgHeight = img.height();
										var imgStyle = {};
		
										/*
		
										 MMImgStyle 会作为 ng-style 设置在图片上，保证返回的给 mm-repeat 的 _h 一定会等于图片真正的高度
										 1. 如果服务器有给出高度，并且是图片类型，那么使用服务器给出的高度，准确性服务器保证
										 2. 如果服务器有给出高度，并且是自定义表情类型，那么根据自定义表情的 img 元素的宽度去按比例算出高度，
										 3. 如果服务器没给出，那么进行预渲染，在 onload 的时候获取高度
										 4. 如果一开始就有高度，那么不需要处理，因为不论来自缓存还是上传插件的预览图，都不需要加载图片的过程，甚至预览图都不用
		
										 在某些浏览器下，图片加载完成前也是有高度的，所以分两种情况:
										 1. imgHeight > 40 的情况，这种情况认为图片横竖加载完成了
										 2. imgHeight > 0 , 并且通过额外条件判断图片是否加载完成
		
		
										 PS：如果图片加载完成，却仍然用 onload 的方式去感知图片加载的话，有可能会遇到 onload 不触发，从而影响 mmrepeat 渲染
										 */
		
										console.log('preload!!!!!!!!!!!!!!!!!!!',
											item,imgHeight > 40 || (img[0].complete == true && !(typeof img[0].naturalWidth && img[0].naturalWidth ===0) && imgHeight > 0),item.ImgHeight)
		
										if(item.ImgHeight){
											// 如果服务器给了高度，则预设高度，不用进行 onload 过程
											if(item.MsgType == confFactory.MSGTYPE_EMOTICON){
												// 自定义表情是 固定宽度的等比缩放
												imgStyle.height = (item.ImgHeight*img.width())/item.ImgWidth + 'px';
												imgStyle.widht = img.width()+'px';
		
											}else{
												imgStyle.height = item.ImgHeight;
												imgStyle.width = item.ImgWidth;
											}
											item.MMImgStyle = imgStyle;
											newScope.$digest();
											cb(domEl.height());
											newScope.$destroy();
											domEl.remove();
		
										}else{
										if(imgHeight > 40 || (img[0].complete == true && !(typeof img[0].naturalWidth && img[0].naturalWidth ===0) && imgHeight > 0)){
											cb(domEl.height());
											newScope.$destroy();
											domEl.remove();
		
										}else{
		
		
												if(item.MMPreviewSrc){
													img[0].onload = onload;
													img[0].onerror = onerror;
													img[0].src = item.MMPreviewSrc;
		
													return ;
												}
		
		
												if(typeof item.MMStatus !== 'undefined' && item.MMStatus !=confFactory.MSG_SEND_STATUS_SUCC){
		
													var unregister = $scope.$watch(function(){
														return item.MMStatus;
													},function(status){
		
														if(status == confFactory.MSG_SEND_STATUS_SUCC){
		
		
															img[0].onload = onload;
															img[0].onerror = onerror;
		
															img[0].src = $scope.getMsgImg(item.MsgId,'slave');
															console.log('preload!!!!!!!!!!!!!!!!!! ',img[0].src)
															unregister();
														}
													})
												}else{
													img[0].onload=onload;
													img[0].onerror = onerror;
												}
		
		
		
		
											}
		
		
		
										}
		
		
		
									}else{
		
		
										newScope.$digest();
										console.log(domEl.height())
										/*todo: 是否需要对异常情况做计算 */
										cb(domEl.height());
										newScope.$destroy();
										domEl.remove();
		
									}
		
									function onload(){
										console.log('height',domEl.height())
		
										imgStyle.height = img.height();
										imgStyle.width = img.width();
										item.MMImgStyle = imgStyle;
		
										cb(domEl.height());
										newScope.$destroy();
										domEl.remove();
									};
									function onerror(e){
		
										console.error(e)
										// todo: 图片加载错误处理
		
		
										reportService.report(reportService.ReportType.imageLoadError,{
											text:'chat content image preload fail',
											src:this.src
										})
		
										imgStyle.height = 110;
										imgStyle.width = 110;
										item.MMImgStyle = imgStyle;
										newScope.$digest();
										cb(domEl.height());
										newScope.$destroy();
										domEl.remove();
									}
								},0)
							})(newScope,domEl,item,cb)
		
						};
		
						$scope.cancelUploadFile = function(msg){
							msg.MMCancelUploadFileFunc(msg);
						};
		
		
						/*setCurrentUnread*/
		
						function clearBottomUnread(){
						  $scope.currentContact && chatFactory.markMsgsRead($scope.currentContact.UserName);
						 /*   chatFactory.setCurrentUnread(chatFactory.getCurrentUserName(),0);*/
							$scope.bottomUnreadCount = 0;
							chatFactory.getChatList();
						}
		
		
					}
				]);
		
		})();
	
	/***/ }),
	/* 278 */,
	/* 279 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Controllers */
		
		angular.module('Controllers')
		.controller('contentContactController', ['$scope', 'contactFactory',function($scope, contactFactory) {
			
			$scope.$watch(function () {
				return contactFactory.getCurrentContact(); 
			}, function (newValue) {
				if (newValue){
					$scope.currentContact = contactFactory.getCurrentContact();
				}
			});
		
		}]);
		})();
	
	/***/ }),
	/* 280 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function(){
		'use strict';
		
		/* Controllers */
		
		angular.module('Controllers')
		.controller('chatSenderController', [
			'$rootScope',
			'$scope',
			'$http',
			'$timeout',
			'ngDialog',
			'confFactory',
			'accountFactory',
			'contactFactory',
			'chatFactory',
			'screenShotFactory',
			'utilFactory',
			'mmpop',
			'stateManageService',
			'emojiFactory',
			'reportService',
			'monitorService',
			function($rootScope, $scope,$http,$timeout,ngDialog,confFactory,accountFactory,contactFactory,chatFactory,screenShotFactory, utilFactory,mmpop,
					 stateManageService,emojiFactory,reportService, monitorService) {
		
				var caretPosHelper = document.getElementById("caretPosHelper"), caretPosLeft = 0, caretPosTop = 0;
				var editArea = document.getElementById("editArea"), editAreaWrp = editArea.parentNode;
				var editAreaSel, editAreaRange;
				var editingContents = utilFactory.getShareObject('editingContents'); // 编辑中的草稿
				var previewIsOpen = false;
				var pasteIng = false;
				var pasteIngTimer = null;
		
		
				function changeHasTextState(){
					var text = (typeof editArea.textContent != 'undefined')?editArea.textContent:editArea.innerText;
					var hasImg = editArea.getElementsByTagName('img').length > 0;
					if(text.length > 0 || hasImg){
						stateManageService.change('sender:hasText',true);
					}else{
						stateManageService.change('sender:hasText',false);
					}
				}
		
		
				function _saveRange(){
		
					if(window.getSelection){
						editAreaSel = window.getSelection();
						editAreaRange = editAreaSel.getRangeAt(0);
					}else{
						editAreaRange = document.selection.createRange();
					}
				}
				function _restoreRange(){
					/*if(!editAreaRange){
						_saveRange();
						return;
					}*/
		
					//editArea.focus();
					if(editAreaRange){
						if(window.getSelection) {
		
							editAreaSel.removeAllRanges();
							editAreaSel.addRange(editAreaRange);
						} else {
							editAreaRange.select();
						}
					}else{
						_moveCaretToEnd();
					}
		
				}
				$(editArea).on('input',function(){
					_saveRange();
				}).on('click',function(){
					_saveRange();
				}).on('paste',function(e){
					var result = chatFactory.setSendFileUsername(chatFactory.getCurrentUserName());
		
		
					if(pasteIngTimer) {
						clearTimeout(pasteIngTimer)
					}
					pasteIng = true;
					pasteIngTimer = setTimeout(function(){
						pasteIng = false;
					},100)
		
		
					if(!result){
						alert(_("599d8df"))
						e.preventDefault();
						e.stopPropagation();
						return false
					}
				})
		
		
				$('#J_CatchDrop').on('drop',function(e){
					e.stopPropagation();  e.preventDefault();
				})
		
		
		
				/**
				 * 把光标移到所有元素的最后
				 */
				function _moveCaretToEnd(){
					var range,selection;
					if(document.createRange){ // Chrome, IE 9+
						range = document.createRange(); // 创建不可见的选区
						range.selectNodeContents(editArea); // 选中整个元素
						range.collapse(false); // 选至尾部，false为尾部，true为头部
						selection = window.getSelection();
						selection.removeAllRanges();
						selection.addRange(range);
					}else if(document.selection){ // IE 8 and lower
						range = document.body.createTextRange();
						range.moveToElementText(editArea);
						range.collapse(false);
						range.select();
					}
				}
				/**
				 * 获取最后输入的字符
				 * @param len 长度，不传则为到头的全部
				 */
				function _getLastCharFromEditArea(len){
					var precedingChar = "", sel, range;
					if (window.getSelection) {
						sel = window.getSelection();
						if (sel.rangeCount > 0) {
							range = sel.getRangeAt(0).cloneRange();
							range.collapse(true);
							range.setStart(editArea, 0);
							precedingChar = range.toString().slice(-len);
						}
					} else if ( (sel = document.selection) && sel.type != "Control") {
						var precedingRange;
						range = sel.createRange();
						precedingRange = range.duplicate();
						precedingRange.moveToElementText(editArea);
						precedingRange.setEndPoint("EndToStart", range);
						precedingChar = precedingRange.text.slice(-len);
					}
					return precedingChar;
				}
				/**
				 * 往编辑区插入内容
				 * @param isEditing 编辑区是否在编辑中
				 */
				function _insertToEditArea(ctn, isEditing){
					var sel, range;
					if (!isEditing) _restoreRange();
		
					if (window.getSelection) { // IE9 and non-IE
						if(!isEditing && editAreaRange){ sel = editAreaSel; range = editAreaRange; }
						else {sel = window.getSelection(); range = sel.getRangeAt(0);  }
						range.deleteContents();
		
						var frag;
						if(range.createContextualFragment){
							frag = range.createContextualFragment(ctn);
						}else{
							var el = document.createElement("div");
							el.innerHTML = ctn;
							frag = document.createDocumentFragment();
							var node, lastNode;
							while ((node = el.firstChild)) {
								lastNode = frag.appendChild(node); // 之所以能终止循环，是因为el的child一旦添加到dom后，作为fragment里的的child就没了。那么el.firstChild就会返回null
							}
						}
						var lastInsertedNode = frag.lastChild; // 为啥在这里保存，原因和上面的注释一致
						range.insertNode(frag);
		
		
						// 把光标挪到插入的元素后面
						range.setStartAfter(lastInsertedNode);
		
						sel.removeAllRanges();
						sel.addRange(range);
		
		
		
						var  shouldOffsetTop = lastInsertedNode.offsetTop - 42/*第一行就已经有的，现在补偿回来*/ + lastInsertedNode.offsetHeight - editArea.offsetHeight
						if(editArea.scrollTop < shouldOffsetTop){
							editArea.scrollTop  =  shouldOffsetTop
						}
					} else { // IE < 9
						range = (isEditing || !editAreaRange) ? document.selection.createRange() : editAreaRange;
						ctn = ctn.replace(/</gi, '&lt;').replace(/>/gi, '&gt;');
						range.pasteHTML(ctn);
						range.select();
					}
				}
				/**
				 * 插入caretPosHelper以获得当前光标的坐标
				 */
				function _calcCaretPos(){
					if(window.getSelection){
						window.getSelection().getRangeAt(0).insertNode(caretPosHelper); // 插入一个元素以记录当前光标在屏幕的位置
						caretPosLeft = caretPosHelper.offsetLeft;
						caretPosTop = caretPosHelper.offsetTop - editArea.scrollTop;
						editAreaWrp.appendChild(caretPosHelper); // 立刻插到body下，免得被擦掉
					}
				}
		
		
				/**
				 * 弹窗展示图片，并确认是否发送
				 * @param msg 需要传入消息，用于sender发送
				 * @return func 用于update src和mediaId
				 */
				function _imgMsgPreview(msg){
		
					var _dialog = ngDialog.open({
						template: 'imageUploadPreview.html',
						controller: ['$scope', function(scope) {
							previewIsOpen = true;
							var mediaId = "";
							scope.src = "";
							scope.send = function(){
		
								if(!mediaId) return;
		
								msg.MediaId = mediaId;
								chatFactory.appendMessage(msg);
								chatFactory.sendMessage(msg);
								ngDialog.close();
								// monitorService.report(monitorService.SEND_MSG_COUNT, 1, 60000);
							};
							scope.cancel = function(){
		
								ngDialog.close();
								msg = null;
							};
							scope.$on("root:uploadImg:success", function(e, data){
								scope.src = data.src;
								msg.MMPreviewSrc = data.src;
								mediaId = data.mediaId;
								scope.$digest();
							});
		
						}],
						className: "default image_preview"
					});
		
					return {
						update: function(src, mediaId){
							$rootScope.$broadcast("root:uploadImg:success", {src: src, mediaId: mediaId});
						},
						close: _dialog.close
					};
				}
		
		
		
				$scope.isDisabled = !$scope.userName;
				$scope.isMacOS = navigator.userAgent.toUpperCase().indexOf("MAC OS") > -1;
				$scope.editAreaCtn = "";
		
				var prevUser ;
				$scope.$on('$destroy', function(){
					if(prevUser){
						editingContents[prevUser] = editArea.innerHTML;
					}
				});
				$scope.$watch(function () {
					return chatFactory.getCurrentUserName();
				}, function (newValue, oldValue) {
					if(oldValue && newValue != oldValue) editingContents[oldValue] = editArea.innerHTML;
		
					prevUser = newValue;
				   setContentAndMoveCare(editingContents[newValue]);
				});
		
				function setContentAndMoveCare(text){
					editArea.innerHTML = $scope.editAreaCtn = text || "";
					editArea.focus();
					changeHasTextState();
					stateManageService.change('sender:active',true);
					if(text){
						_moveCaretToEnd();
						_saveRange()
					}
				}
		
				$scope.showEmojiPanel = function (e) {
				  //  _saveRange(); // 保存editArea的选区
					/*setTimeout(function(){
						editArea.focus();
					},0)*/
					mmpop.toggleOpen({
						top: -272,
						left: 15,
						templateUrl: "expression.html",
						className: "slide-top",
						controller: "emojiController",
						singletonId:'mmpop_emoji_panel',
						scope: $scope,
						autoFoucs:false,
						container: angular.element(document.getElementById('tool_bar'))
					});
					e.preventDefault();
				};
				var prevTimeStamp ;
				$scope.sendClick = function(e){
					var result = chatFactory.setSendFileUsername(chatFactory.getCurrentUserName());
		
					if(!result){
		
						if(!prevTimeStamp || (e.timeStamp - prevTimeStamp > 30)){
							prevTimeStamp = e.timeStamp;
							alert(_("599d8df"))
						}
		
						e.preventDefault();
						e.stopPropagation();
						return false
					}
				}
				$scope.screenShot = function(){
					var uploadPreview;
					if (screenShotFactory.isSupport()) {
						screenShotFactory.capture({
							ok : function(){
								var msg = chatFactory.createMessage({
									MsgType: confFactory.MSGTYPE_IMAGE,
									Type: confFactory.MSGTYPE_IMAGE
								});
								uploadPreview = _imgMsgPreview(msg);
								screenShotFactory.upload(JSON.stringify(msg), function(ret) {
									if (!ret.BaseResponse || ret.BaseResponse && ret.BaseResponse.Ret != 0) {
										alert(_("76a7e04"));
										uploadPreview.close();
									} else {
										console.log("capture upload success");
										uploadPreview.update(confFactory.API_webwxpreview + "?fun=preview&mediaid=" + ret.MediaId, ret.MediaId);
									}
								});
							}
						});
		
					}else {
						if(navigator.platform == "Win64" && utilFactory.browser.msie) alert(_("82cf63d"));
						else if(confirm(_("112a5c0"))) screenShotFactory.install();
					}
					monitorService.report(monitorService.CLICK_SNAPSHOT_COUNT, 1);
				};
				/*$scope.editAreaPaste = function(e){ // 就算这里给file增加自定义属性，在uploader那里还是会被洗掉，故注释。。。
					var item = (e.clipboardData || e.originalEvent.clipboardData).items[0], blob;
					if (item.kind == 'file' && item.type.match(/^image\//i) && (blob = item.getAsFile())) {
						var file = new WebUploader.Lib.File(WebUploader.guid(), blob); // 这里没有直接调用API的File，而是看了源码之后调用Lib里面的File，目的是为了和源码里的粘贴方法一致
						fileExtend(file, {
							onSuccess: emptyFunc
						});
						uploader.addFile(file);
					}
				};*/
				var atTimeout,nextHandler;
				$scope.editAreaKeyup = function(e){
					if(!MMDEV) return;
		
		
		
		
					if(e.keyCode == confFactory.KEYCODE_NUM2 && _getLastCharFromEditArea(1) == "@"){
						var currentUserName = chatFactory.getCurrentUserName();
						if(!utilFactory.isRoomContact(currentUserName)) return;
		
						_calcCaretPos();
						nextHandler = function(){
							atTimeout = null;
							nextHandler = null;
							var memberList = contactFactory.getChatRoomMembersContact(currentUserName, "withoutMe");
							//if(!memberList.length || !memberList[0].HeadImgUrl) return; // 没有群成员列表 或 群成员具体数据还没回来，先不展示
		
							_saveRange();
							mmpop.open({
								templateUrl: "editAreaContactPanel.html",
								controller: "editAreaContactListController",
								left: caretPosLeft,
								top: caretPosTop,
								scope: {
									chatRoomUserName: currentUserName,
									memberList: angular.copy(memberList),
									insertContactToEditArea: $scope.insertToEditArea
								},
								autoFoucs: false,
								container: angular.element(editAreaWrp)
							});
		
						};
		
						// 如果距上次操作超过 300ms 则马上执行，如果没操过，则延迟
						if(!atTimeout  && nextHandler) {
							nextHandler();
						}
		
						clearTimeout(atTimeout);
						atTimeout = setTimeout(function(){ // 设置延时是因为防止被人狂@
						  nextHandler && nextHandler();
						  atTimeout = null;
						}, 300);
					}
				};
				$scope.editAreaKeydown = function(e){
					changeHasTextState();
					if (atTimeout) {
						e.preventDefault();
						return;
					}
		
					var keyCode = e.keyCode;
					if(keyCode == confFactory.KEYCODE_ENTER){
						if(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey){
							var ctn = "<br>";
							if (!utilFactory.browser.msie && window.getSelection){
								var nextSibling = window.getSelection().focusNode.nextSibling;
								do{ // 如果找到 非空节点 || 值为非空节点 || <br> 就跳出
									if(!nextSibling || nextSibling.nodeValue || nextSibling.tagName == "BR") break;
								}while(nextSibling = nextSibling.nextSibling);
								if(!nextSibling){
									ctn += ctn; // 后面没有node的时候需要两个<br>
								}
							}
							$scope.insertToEditArea(ctn, true);
							editArea.scrollTop = editArea.scrollHeight;
						}else{
							$scope.sendTextMessage();
						}
						e.preventDefault();
					}
					// alt + s
					if(keyCode==83 && e.altKey){
						$scope.sendTextMessage();
						e.preventDefault();
					}
		
					// 可视字符
					if(keyCode >=65 && keyCode <=111 || keyCode >=186 && keyCode <=222){
						mmpop.close();
					}
		
		
				};
				$scope.editAreaBlur = function(e){
					nextHandler = null;
					stateManageService.change('sender:active',false);
				};
				$scope.editAreaClick = function(e){
					_calcCaretPos();
				};
				$scope.sendTextMessage = function () {
					mmpop.close();
					if ($scope.editAreaCtn.replace(/<br\/?>/g,"").match(/^\s*$/)){// <br> || <br/>
						return;
					}
		
		
		
					var msg = chatFactory.createMessage({
						MsgType: confFactory.MSGTYPE_TEXT,
						Content: $scope.editAreaCtn
					});
					chatFactory.appendMessage(msg);
					chatFactory.sendMessage(msg);
		
					editingContents[chatFactory.getCurrentUserName()] = '';
					$scope.editAreaCtn = '';
				};
		
				$scope.$on("root:quoteMsg",function(e,text){
		
					setContentAndMoveCare(text + (editArea.innerHTML.replace('<br>','')?editArea.innerHTML:'<br>'));
					editArea.scrollTop = 9999;
				});
		
		
				/**
				 * 插入内容到编辑区
				 * @param ctn 内容，可以是html
				 * @param isEditing 焦点是否在编辑区中。如果不是，则需要读取range
				 */
				$scope.insertToEditArea = function (ctn, isEditing) {
					_insertToEditArea(ctn, isEditing);
					$scope.editAreaCtn = editArea.innerHTML;
				};
				/**
				 * 发送兔斯基表情
				 * @param md5 兔斯基的MD5，可以在emojiService里面找到
				 */
				$scope.sendTuzkiEmoji = function(md5, name){
		
					var msg = chatFactory.createMessage({
						MsgType : confFactory.MSGTYPE_EMOTICON,
						Content: md5,
						EmojiFlag : confFactory.EMOJI_FLAG_GIF,
						EMoticonMd5 : md5
					});
		
					msg.MMPreviewSrc =  confFactory.RES_PATH + "images/icon/Tuzki/" + name;
					chatFactory.appendMessage(msg);
					chatFactory.sendMessage(msg);
				};
		
				$scope.sendGif = function(MediaId){
		
				}
		
		
				//文件上传，使用FEX的uploader，API见：http://fex-team.github.io/webuploader/doc/index.html#Lib.File
				var MAX_IMG_UPLOAD_SIZE = 20//10;//10M
				var MAX_FILE_UPLOAD_SIZE = 50;//20M
				var NEED_CHECK_SIZE = 25;//20M
		
		
				var accessImageExts = {"bmp": 1, "png": 1, "jpeg": 1, "jpg": 1, "gif": 0}; // 图片规则
				function isImg(ext){
					return accessImageExts[ext.toLowerCase()];
				}
				function getMsgType(ext){
					var accessVideoExts = {
						'mp4':1
					};
					if(isImg(ext)){
						return confFactory.MSGTYPE_IMAGE;
					} else if(accessVideoExts[ext.toLowerCase()]){
						return confFactory.MSGTYPE_VIDEO;
					} else{
						return confFactory.MSGTYPE_APP;
					}
				}
		
				var _cancelUploadFile = function(msg){
					uploader.cancelFile(msg.MMFileId);
		
					msg.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_CANCEL;
					msg.MMStatus = confFactory.MSG_SEND_STATUS_READY;
				};
				var emptyFunc = function(){},
					chooseFileCbs = { // 选择文件 背景下的回调
						onQueued: function(){
							if(isImg(this.ext) || this.ext.toLowerCase() == 'gif'){
								if(this.ToUserName != chatFactory.getCurrentUserName()){
									utilFactory.reportSendState('sendImageWrong')
									reportService.report(reportService.ReportType.sendError,{
										type:'sendImageWrong',
										browser:utilFactory.browser.msie?'ie':'other'
									})
								}
							}
		
		
							if(this.ext.toLowerCase() == 'gif'){
								this.MMSendMsg = chatFactory.createMessage({
									ToUserName:this.ToUserName,
									MsgType : confFactory.MSGTYPE_EMOTICON,
									EmojiFlag : confFactory.EMOJI_FLAG_GIF/*,
									MediaId:MediaId*/
								});
		
		
								/*  msg.MMPreviewSrc =confFactory.API_webwxgetmsgimg + '?'+'&MsgID='+ msgId +'&skey=' + encodeURIComponent(accountFactory.getSkey())*/
		
		
								(function(f){
		
									uploader.makeThumb(f, function(error, blob) {// 创建缩略图，如果有的话返回blob
		
										if(blob) f.MMSendMsg.MMThumbSrc = blob;
										chatFactory.appendMessage(f.MMSendMsg);
									console.log(blob)
									},1,1);
								})(this);
								return ;
							}
		
		
							if(isImg(this.ext)){
								var msgtype = getMsgType(this.ext);
		
								this.MMSendMsg = chatFactory.createMessage({ // 创建消息
									ToUserName:this.ToUserName,
									MsgType: msgtype,
									FileName: this.name, // 文件名字
									FileSize: this.size, // 文件大小
									MMFileId: this.id, // 文件在uploader的id
									MMFileExt: this.ext, // 文件后缀名
									MMUploadProgress: 0, // 上传进度
									MMFileStatus: confFactory.MM_SEND_FILE_STATUS_QUEUED, // 文件状态，现在是插入队列，待发送
		
									MMCancelUploadFileFunc: _cancelUploadFile
								});
								(function(f){
									f.MMSendMsg.MMThumbSrc = "";
									uploader.makeThumb(f, function(error, blob) {// 创建缩略图，如果有的话返回blob
		
										if(error || !blob){
											reportService.report(reportService.ReportType.uploaderError,{
												text:'创建缩略图失败',
												fileName: f.MMSendMsg.MMFileExt,
												fileSize: f.MMSendMsg.FileSize
											})
										}
		
										if(blob) f.MMSendMsg.MMThumbSrc = blob;
		
										// todo 如果预览出错，则插入默认占位图
										chatFactory.appendMessage( f.MMSendMsg);
		
										$rootScope.$digest();
									});
								})(this);
							}
						},
						onProgress: function(percentage){
		
		
		
							var me = this;
		
							$scope.$apply(function(){
								if(me.MMSendMsg){
									me.MMSendMsg.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_SENDING;
									me.MMSendMsg.MMUploadProgress = parseInt(percentage * 100);
								}
							});
						},
						onSuccess: function(res){
							if(res.BaseResponse.Ret == 0){
								var msg = this.MMSendMsg;
								msg.MediaId = res.MediaId;
								msg.Signature = this.Signature;
								msg.EncryFileName = res.EncryFileName;
								chatFactory.sendMessage(msg);
		
								msg.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_SUCCESS;
								if(!$scope.$$phase) $scope.$digest();
		
		
							}else{
								this.onError("Ret: " + res.BaseResponse.Ret);
							}
						},
						onError: function(reason){
							var me = this;
		/*                    console.error(me.name + " uploadError: ", reason);*/
		
							reportService.report(reportService.ReportType.uploaderError,{
								text:'chooseFile 上传失败',
								reason:reason,
								fileName: this.ext,
								fileSize: this.size
							});
		
							$scope.$apply(function(){
								me.MMSendMsg.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_FAIL;
								me.MMSendMsg.MMStatus = confFactory.MSG_SEND_STATUS_FAIL;
							});
						}
					},
					pasteImgCbs = {
						onQueued: function(){
							var msg = chatFactory.createMessage({
								ToUserName:this.ToUserName,
								MsgType: confFactory.MSGTYPE_IMAGE,
								Type: confFactory.MSGTYPE_IMAGE
							});
		
						   /* if(isImg(this.ext)) {
								(function (f) {
									msg.MMThumbSrc = "";
									uploader.makeThumb(f, function (error, blob) {// 创建缩略图，如果有的话返回blob
										if (blob) msg.MMThumbSrc = blob;
									});
								})(this);
							}*/
		
		
								this._uploadPreviewUpdate = _imgMsgPreview(msg).update;
						},
						onSuccess: function(res){
							if(res.BaseResponse.Ret == 0){
								this._uploadPreviewUpdate(confFactory.API_webwxpreview + "?fun=preview&mediaid=" + res.MediaId, res.MediaId);
							}else{
								this.onError("Ret: " + res.BaseResponse.Ret);
							}
						},
						onError: function(reason){
							//console.error(this.name + " uploadError: ", reason);
							reportService.report(reportService.ReportType.uploaderError,{
								text:'pasteImg 上传失败',
								reason:reason,
								fileName: this.ext,
								fileSize: this.size
							});
							alert(_("c5795a7") + reason);
						}
					};
				/**
				 * 为文件对象增加回调方法，以供uploader调用，默认的回调是在 选择文件 背景下的回调
				 */
				function fileExtend(file, cbs){
					angular.extend(file, {
						onQueued: emptyFunc,
						onProgress: emptyFunc,
						onSuccess: emptyFunc,
						onError: emptyFunc
					}, cbs);
				}
		
				var uploader;
				function initWebUploader(){
					__webpack_require__.e/* nsure */(3, function(require){
						var WebUploader = __webpack_require__(281);
						window.WebUploader = WebUploader;
						// 系统没有安装flash、浏览器不支持H5上传时，傻逼webuploader会抛出异常，要自己捕获
						try{
							uploader = WebUploader.create({
								auto: true,
								dnd: "#chatArea",
								paste: utilFactory.browser.webkit?"#chatArea":undefined,
								swf: confFactory.RES_PATH + "third_party/webuploader-0.1.5/Uploader.swf",
								server: confFactory.API_webwxuploadmedia + "?f=json",
								//threads: 1, // 设置进程为1是为了确保顺序
								fileVal: "filename",
								pick: ".js_fileupload",
								compress:false,
								duplicate:true,
								threads:1,
								chunked:true,
								chunkSize:524288,
								withCredentials: true
							})
								.on("beforeFileQueued", function(file){ // 添加到队列前触发
									var self = this;
									if(file._checked) return true;
		
									monitorService.report(monitorService.UPLOAD_COUNT, 1);
									// utilFactory.reportSendState('sendFile');
		
									if(file.size == 0){
										uploader.skipFile(file);
										alert(_("61e885c"))
										return false;
									}
		
		
									file._data = file._data || {
		
									}
								/*    if(isImg(file.ext)){
										if(file.size > MAX_IMG_UPLOAD_SIZE * 1024 * 1024){
											alert(_("8c88ff6") + MAX_IMG_UPLOAD_SIZE + "M");
											return false;
										}
									}else{
										if(file.size > MAX_FILE_UPLOAD_SIZE * 1024 * 1024){
											alert(_("0c9c48a") + MAX_FILE_UPLOAD_SIZE + "M");
											return false;
										}
									}
									*/
		
									if(!chatFactory.getSendFileUsername()){
										uploader.skipFile(file);
										alert(_("599d8df"))
										return false;
									}
		
									if(/untitled\d+.png/i.test(file.name) || pasteIng){
										fileExtend(file, pasteImgCbs);
										file.ToUserName = chatFactory.getSendFileUsername()
		
									} // TODO 暂时只能以这么龊的方式区分是file是来自 剪切板 还是 文件选择器
									else {
										// if(!file.ToUserName){
											file.ToUserName = chatFactory.getSendFileUsername();
										// }
										fileExtend(file, chooseFileCbs); // 文件必须有对应状态的回调方法，这里是当来到这里没有时，当作来自 文件选择器 处理
										if(file.ext.toLowerCase() !== 'gif' && !isImg(file.ext)){
											var msgtype = getMsgType(file.ext);
		
											if(msgtype == confFactory.MSGTYPE_VIDEO && file.size >= MAX_IMG_UPLOAD_SIZE * 1024 * 1024){
												uploader.skipFile(file);
												alert(_("9a7dbbc"))
												return;
											}
		
		
											if(file.ToUserName != chatFactory.getCurrentUserName()){
												utilFactory.reportSendState('sendFileWrong')
												reportService.report(reportService.ReportType.sendError,{
													type:'sendFileWrong',
													browser:utilFactory.browser.msie?'ie':'other'
												});
											}
											file.MMSendMsg = chatFactory.createMessage({ // 创建消息
												ToUserName:file.ToUserName,
												MsgType: msgtype,
												FileName: file.name, // 文件名字
												FileSize: file.size, // 文件大小
												MMFileId: file.id, // 文件在uploader的id
												MMFileExt: file.ext, // 文件后缀名
												MMUploadProgress: 0, // 上传进度
												MMFileStatus: confFactory.MM_SEND_FILE_STATUS_SENDING, // 文件状态，现在是插入队列，待发送
											 /*   Signature:file.Signature,*/
												MMCancelUploadFileFunc: _cancelUploadFile
											});
											chatFactory.appendMessage(file.MMSendMsg);
											if(!$scope.$$phase) $scope.$digest();
										}
									}
		
		
									var needCheck = false;
									if(file.size > NEED_CHECK_SIZE * 1024 * 1024){
										needCheck = true;
									}
		
		
		
		
		
									var startTime = Date.now();
									uploader.md5File( file )
										.then(function(val) {
											console.log('md5 result:', val);
											var time = Date.now() - startTime;
											var timeConsuming = (time / file.size)*1024*1024;
											if(file.size > 1024*1024){
												utilFactory.reportSendState('MD5TimeBigFilePerMb',Math.floor(timeConsuming));
												utilFactory.reportSendState('MD5TimeBigFilePerMbCount');
											}else{
												utilFactory.reportSendState('MD5TimeSmallFile',time);
												utilFactory.reportSendState('MD5TimeSmallFileCount');
											}
		
											var fileInfo;
											var fileMsgInfo =  {
												FromUserName: accountFactory.getUserName(),
												ToUserName: file.ToUserName,
												FileSize: file.size,
												FileMd5:val,
												FileName:file.name,
												FileType:7 // 大文件
											};
											if(needCheck){
		
												var postData = angular.extend(fileMsgInfo, accountFactory.getBaseRequest());
		
												fileInfo =  angular.extend({},fileMsgInfo);
		
												$http({
													method :'POST',
													url:confFactory.API_checkupload,
													data:postData
												}).success(function(res){
													if(res.BaseResponse.Ret == 0){
														fileInfo =  angular.extend(fileInfo,{
															AESKey:res.AESKey,
															Signature:res.Signature
														});
														file.Signature = res.Signature;
		
														upload(file,res.MediaId,res)
													}else{
														if(  file.MMSendMsg){
															file.MMSendMsg.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_FAIL;
															file.MMSendMsg.MMStatus = confFactory.MSG_SEND_STATUS_FAIL;
														}
														alert(res.BaseResponse.ErrMsg)
													}
		
												}).error(function(err){
													if(  file.MMSendMsg) {
														file.MMSendMsg.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_FAIL;
														file.MMSendMsg.MMStatus = confFactory.MSG_SEND_STATUS_FAIL;
													}
													alert('上传失败')
												});
											}else{
		
												fileInfo =  angular.extend({},fileMsgInfo);
												upload(file)
											}
		
											function upload(file,mediaId,res){
												// 准备 upload 参数
												var uploadmediarequestBase = angular.extend(accountFactory.getBaseRequest(),{
													ClientMediaId: utilFactory.now(),
													TotalLen: file.size,
													StartPos: 0,
													DataLen: file.size,
													MediaType: confFactory.UPLOAD_MEDIA_TYPE_ATTACHMENT,
		
													FromUserName:fileInfo.FromUserName,
													ToUserName:fileInfo.ToUserName,
													FileMd5:fileInfo.FileMd5,
													AESKey:fileInfo.AESKey,
													Signature:fileInfo.Signature
												});
		
		
												var msgType = getMsgType(file.ext),mediaType;
												switch(msgType){
													case confFactory.MSGTYPE_IMAGE:
														mediaType = 'pic';break;
													case confFactory.MSGTYPE_VIDEO:
														mediaType = 'video';break;
													default: mediaType = 'doc';
												}
		
		
												var uploadParams = {
													mediatype : mediaType,
													uploadmediarequest : JSON.stringify(angular.extend(
														{
															UploadType:1
														},uploadmediarequestBase
													)),
													webwx_data_ticket : utilFactory.getCookie('webwx_data_ticket'),
													pass_ticket : decodeURIComponent(accountFactory.getPassticket())
												}
		
		
												file._uploadParams = uploadParams;
												file._uploadmediarequestBase = uploadmediarequestBase;
		
												if(mediaId){
													uploader.trigger('fileQueued',file)
													uploader.trigger('uploadSuccess',file,res)
													uploader.skipFile(file);
		
												}else{
													file._checked = true;
													uploader.addFiles(file);
												}
		
		
											}
										});
		
		
		
		
									return false;
		
								})
								.on("fileQueued", function(file){ // 当有文件添加到队列时触发
									file.onQueued.call(file);
								})
							  /*  .on("filesQueued", function(files){ // 当有文件添加到队列时触发
									for (var i = 0, len = files.length; i < len; ++i) {
										var file = files[i];
										file.onQueued.call(file);
									}
								})*/
								.on("uploadBeforeSend", function(obj, data, headers){ // 在文件发送前触发
									var file = obj.file;
									var fileInfo = file._data || {};
									angular.extend(data,
										file._uploadParams,
										{
											uploadmediarequest:JSON.stringify(angular.extend(
												{
													UploadType:2
												},file._uploadmediarequestBase
											))
										});
								})
								.on("uploadProgress", function(file, percentage){
									file.onProgress.call(file, percentage);
								})
								.on("uploadFinished", function(){
									uploader.reset(); // 上传完之后重置队列（失败的文件也会被去掉）
								})
								.on("uploadSuccess", function(file, response){
									file.onSuccess.call(file, response);
								})
								.on("uploadError", function(file, reason){
									file.onError.call(file, reason);
									monitorService.report(monitorService.UPLOAD_FAIL_COUNT, 1);
								})
								.on("error", function(type){
									reportService.report(reportService.ReportType.uploaderError,{
										text:'WebUploader 出错',
										type:type
									});
									monitorService.report(monitorService.UPLOAD_FAIL_COUNT, 1);
								});
						}catch(err){
							$scope.noflash = true;
							reportService.report(reportService.ReportType.uploaderError,{
								text:'WebUploader 出错',
								type: 'no_flash'
							})
						}
					});
				}
				if(window.WebUploader){
					initWebUploader();
				}else{
					$rootScope.$on('root:pageInit:success',function(){
						initWebUploader();
					});
				}
		
			}]);
		})();
	
	
	/***/ }),
	/* 281 */,
	/* 282 */
	/***/ (function(module, exports) {
	
		(function () {
		'use strict';
		
		/* Controllers */
		
		angular.module('Controllers')
			.controller('emojiController', ['$rootScope', '$scope', '$timeout', 'emojiFactory', 'confFactory', 'utilFactory',
			function ($rootScope, $scope, $timeout, emojiFactory, confFactory, utilFactory) {
		
				$timeout(function () {
					$scope.QQFaceList = emojiFactory.QQFaceList;
					$scope.EmojiList = emojiFactory.EmojiList;
					$scope.TuzkiList = emojiFactory.TuzkiList;
				},100);
		
				$scope.index = 1;
				$scope.RES_PATH = confFactory.RES_PATH;
		
				$scope.selectEmoticon = function(e){
					var target = e.target;
					if(target.tagName != "A") return;
		
					var content = target.innerText || target.textContent, type = target.getAttribute("type");
					switch(type){
						case "qq":
							content = "[" + content + "]";
							if(!(utilFactory.browser.msie && utilFactory.browser.version < 9)) content = emojiFactory.getEmoticonByText(content);
							$scope.insertToEditArea(content);
							break;
						case "emoji":
							content = "<" + content + ">";
							if(!(utilFactory.browser.msie && utilFactory.browser.version < 9))  content = emojiFactory.getEmoticonByText(content);
							$scope.insertToEditArea(content);
							break;
						case "Tuzki":
							$scope.sendTuzkiEmoji(emojiFactory.getMd5ByTuzki(content), content);
						   /* $timeout(function(){
		
								$rootScope.$digest();
							},0)*/
		
		
						   //
							break;
		
					}
					e.preventDefault();
				};
			}]);
		})();
	
	/***/ }),
	/* 283 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Controllers */
		
		angular.module('Controllers')
		.controller('createChatroomController', [
			'$rootScope',
			'$scope',
			'$timeout',
			'$state',
			'$log',
			'$document',
			'chatFactory', 
			'contactFactory', 
			'appFactory',
			'chatroomFactory',
			'confFactory',
			'mmpop',
			'ngDialog',
			'utilFactory',
			'stateManageService',
				'accountFactory',
				'monitorService',
			function($rootScope, $scope, $timeout,$state, $log, $document, chatFactory,contactFactory, appFactory, chatroomFactory,confFactory, mmpop, ngDialog, utilFactory,stateManageService,accountFactory, monitorService) {
		
		
		
				// 延时是为了先显示mmpop
				$timeout(function() {
		
					if($scope.ngDialogData.isCreate){
						filterContacts = [];
					}
					$scope.allContacts = contactFactory.pickContacts(['star','friend'],{
						star:{
							filterContacts:filterContacts
						},
						friend:{
							filterContacts:filterContacts,
							isWithoutStar:true,
							isWithoutBrand:true
						}
					},true).result;
		
					$scope.chatroomContacts =  contactFactory.pickContacts(['chatroom'],{
						chatroom:{
							noHeader:true
						}
					},true).result;
				}, 100);
				
				$scope.selectedUsers = $scope.ngDialogData.initSelectedContacts || [];
		
				/**
				 * 检索群聊联系人
				 * @return {[type]} [description]
				 */
				var searchTimer,
					searchList,
					searFilterContacts,
					filterContacts = $scope.ngDialogData.isCreate ? {}:chatroomFactory.getFilterContacts();
				function _pickContact(){
					return contactFactory.pickContacts(['friend'], {
						friend: {
							isNewArray: true,
							isWithoutBrand: true,
							keyword: $scope.keyword,
							filterContacts: searFilterContacts,
							noHeader:true
						}
					},true).result;
				}
		
				$scope.pickConfig = {
					types:['star','friend'],
					opt:{
						star:{
		
						},
						friend:{
							isWithoutStar:true,
							isWithoutBrand:true
						},
						all:{
							filterContacts:filterContacts
						}
		
					}
				}
		
		
				/**
				 * 确认添加联系人到群聊
				 */
				$scope.add = function () {
					var currentContact = chatroomFactory.getCurrentContact(),
						addMemberUserNames = [];
					angular.forEach($scope.selectedUsers,function (contact) {
						addMemberUserNames.push(contact.UserName);
					});
					chatroomFactory.addMember(currentContact.UserName,addMemberUserNames.join(','),function (data) {
						if(data.BaseResponse && data.BaseResponse.Ret != 0 && data.BaseResponse.Ret != -2013){
							ngDialog.openConfirm({
								className:'default ',
								templateUrl: 'comfirmTips.html',
								controller:['$scope',function(scope){
									scope.title = _("02d9819");
									scope.content = data.BaseResponse.ErrMsg || _("f45a3d8");
									scope.callback = function () {
										scope.closeThisDialog();
									};
								}]
							});
							monitorService.report(monitorService.INVITE_TO_CHAT_ROOM_FAIL_COUNT, 1);
						}
						//$scope.closeThisDialog();
					});
					$scope.closeThisDialog();
					monitorService.report(monitorService.INVITE_TO_CHAT_ROOM_COUNT, 1);
				};
				/**
				 * 新建群聊
				 */
				$scope.create = function () {
					var memberList = [];
		
					angular.forEach($scope.selectedUsers, function (item,index) {
						if(item.UserName == accountFactory.getUserName()){
							$scope.selectedUsers.splice(index,1);
							return;
						}
					});
		
					if($scope.selectedUsers.length === 1){
						$state.go('chat',{userName:$scope.selectedUsers[0].UserName});
						$scope.closeThisDialog();
						return;
					}
		
					angular.forEach($scope.selectedUsers,function (contact) {
						//if(contact.UserName != accountFactory.getUserName()){
							memberList.push({
								UserName:contact.UserName
							});
						//}
					});
					chatroomFactory.create(memberList).then(function (data) {
						if(data.BaseResponse && data.BaseResponse.Ret == 0  || data.BaseResponse.Ret == -2013){
							//chatFactory.addChatList([data.ChatRoomName]);
							$state.go('chat',{userName:data.ChatRoomName});
							console.log('careate chat room success. chatroom userName:',data.ChatRoomName);
						}else{
							ngDialog.openConfirm({
								className:'default ',
								templateUrl: 'comfirmTips.html',
								controller:['$scope',function(scope){
									scope.title = _("02d9819");
									scope.content = data.BaseResponse.ErrMsg || _("0d42740");
									scope.callback = function () {
										scope.closeThisDialog();
									};
								}]
							});
							monitorService.report(monitorService.CREATE_CHAT_ROOM_FAIL_COUNT, 1);
						}
					},function (data) {
						ngDialog.openConfirm({
							className:'default ',
							templateUrl: 'comfirmTips.html',
							controller:['$scope',function(scope){
								scope.title = _("02d9819");
								scope.content = data.BaseResponse.ErrMsg || _("0d42740");
								scope.callback = function () {
									scope.closeThisDialog();
								};
							}]
						});
						monitorService.report(monitorService.CREATE_CHAT_ROOM_FAIL_COUNT, 1);
					});
					$scope.closeThisDialog();
					monitorService.report(monitorService.CREATE_CHAT_ROOM_COUNT, 1);
				}
		
				/**
				 * 选择一个群聊
				 */
				$scope.selectChatroom = function (contact) {
					$state.go('chat',{userName:contact.UserName});
					$scope.closeThisDialog();
				}
		
		
		
				$scope.chatRoomHeightCalc = function(){
					return 64;
				}
		
		
		
			}
		]);
		
		})();
	
	/***/ }),
	/* 284 */
	/***/ (function(module, exports) {
	
		(function () {
			'use strict';
		
			/* Controllers */
		
			angular.module('Controllers')
				.controller('contextMenuController', [
					"$rootScope",
					"$scope",
					"$state",
					"contextMenuFactory",
					"accountFactory",
					"confFactory",
					'contactFactory',
					'ngDialog',
					'chatroomFactory',
					'emojiFactory',
					'utilFactory',
					'chatFactory',
					function ($rootScope, $scope, $state, contextMenuFactory, accountFactory, confFactory, contactFactory,ngDialog,chatroomFactory,emojiFactory,utilFactory,chatFactory) {
					/*if(ZeroClipboard.isFlashUnusable()){
					 alert(_("7d5c8ce"));
					 }*/
					$scope.$on('app:contextMenu:show', function (e, contextMenuEvent) {
						//console.log(contextMenuEvent,'showContextMenu');
						showContextMenuHandler(contextMenuEvent);
					});
		
					$scope.$on('app:contextMenu:hide', function (e, contextMenuEvent) {
						$scope.isShowContextMenu = false;
					});
		
					/*$scope.$watch(function () {
					 return contextMenuFactory.getContextMenuEventTimeStamp();
					 }, function (newValue,oldValue) {
					 if (newValue != oldValue){
					 var e = contextMenuFactory.getContextMenuEvent();
					 showContextMenuHandler(e);
					 }
					 });*/
		
					function showContextMenuHandler(e) {
						var iePaths = [e.target];
		
						function pushParentNode(el) {
							if (el.parentNode != el.document) {
								iePaths.push(el.parentNode);
								return pushParentNode(el.parentNode);
							} else {
								return iePaths;
							}
						}
		
						var paths = e.path || e.originalEvent.path || pushParentNode(e.target);
						for (var i = 0, len = paths.length; i < len; i++) {
							var cm = angular.element(paths[i]).attr('data-cm');
							if (cm) {
								cm = JSON.parse(cm);
								$scope.isShowContextMenu = true;
								$scope.contextStyle = {
									"top": e.pageY,
									"left": e.pageX
								};
								//$scope.contextMenuTop = e.pageY;
								//$scope.contextMenuLeft = e.pageX;
								switch (cm.type) {
									case 'chat':
										showChatContextMenu(cm.username);
										e.preventDefault();
										break;
									case 'clean':
										showCleanContextMenu(cm.username);
										e.preventDefault();
										break;
									case 'avatar':
										showAvatarContextMenu(e, cm.username, cm.isFriend);
										e.preventDefault();
										break;
									case 'message':
										showMessageContextMenu(cm.actualSender, cm.msgType,cm.subType, cm.msgId, e);
										break;
								}
								var cmEl = angular.element(document.getElementById('contextMenu')),
									winEl = angular.element(window),
									cmw = cmEl.width(),
									cmh = cmEl.height(),
									winw = winEl.width(),
									winh = winEl.height();
		
								if (winw - e.pageX < 400) {
									$scope.contextStyle['right'] = winw - e.pageX;
									$scope.contextStyle['left'] = 'auto';
		
									// $scope.contextStyle = {
									//     "top": e.pageY,
									//     "right": winw - e.pageX
									// };
									//$scope.contextMenuLeft = e.pageX - cmw;
								}
								if (winh - e.pageY < 400) {
		
									$scope.contextStyle['bottom'] =  winh - e.pageY
									$scope.contextStyle['top'] = 'auto';
									//$scope.contextMenuTop = e.pageY - cmh;
								}
								break;
							}
						}
					}
		
					function showChatContextMenu(userName) {
						$scope.contextMenuList = [];
						var contact = contactFactory.getContact(userName);
						// 普通联系人还有群聊好友才能置顶
						if( contact.isRoomContact()|| contact.isContact()){
							if(contact.isTop()){
								$scope.contextMenuList.push( {
										content: _("84e4fac"),
										callback: function () {
											contactFactory.setTopContact(userName,false);
										}
									}
								)
							}else{
								$scope.contextMenuList.push( {
										content: _("3d43ff1"),
										callback: function () {
											contactFactory.setTopContact(userName,true);
										}
									}
								)
							}
		
						}
		
						//editorDialog.html
						if(contact.isRoomContact()){
							$scope.contextMenuList.push( {
								content: _("1f9be6d"),
								callback: function () {
									var _dialog = ngDialog.open({
		
										className: "default chatroom_topic",
										template: 'editorDialog.html',
										controller: ['$scope', function(scope,element) {
											scope.keypress = function (e) {
												var len = $('.chatroom_topic .chatroom_name').text().length;
												if ([8, 37, 39, 46].indexOf(e.keyCode) === -1 && len > 17){
													e.preventDefault();
												}
											};
											scope.text = emojiFactory.transformSpanToImg(contact.getDisplayName());
											scope.send = function(){
												var text = $('.chatroom_topic .chatroom_name').text();
												if (text.length > 17){
													text = text.substring(0, 18);
												}
												if(text.length > 0 && text !=contact.getDisplayName()){
													chatroomFactory.modTopic(contact.UserName,emojiFactory.formatHTMLToSend(text));
												}
		
												ngDialog.close();
											};
											scope.cancel = function(){
												ngDialog.close();
											};
										}]
									});
		
		
								}
							})
						}
		
		
						$scope.contextMenuList.push( {
							content: _("685739c"),
							callback: function () {
								$rootScope.$broadcast("root:deleteChat", userName);
							}
						})
					}
		
				   /* function showNavContactContextMenu(userName) {
						$scope.contextMenuList = [
							{
								content: _("3d43ff1"),
								callback: function (userName) {
									contactFactory.setTopContact();
								}
							},
							{
								content: _("685739c"),
								callback: function () {
									$rootScope.$broadcast("root:deleteChat", userName);
								}
							}
						];
					}*/
		
					function showCleanContextMenu(userName) {
						$scope.contextMenuList = [
							{
								content: _("91382d9"),
								callback: function () {
									$rootScope.$broadcast("root:cleanMsg", userName);
								}
							}
						];
					}
		
					function showAvatarContextMenu(event, userName, isFriend) {
						var list = [
							{
								content: _("7068541"),
								callback: function () {
									$rootScope.$broadcast("root:profile", {
										userName: userName,
										event: event
									});
								}
							}
						];
		
						if (isFriend == "true") {
							list.push({
								content: _("b5f1591"),
								callback: function () {
									$state.go('chat', {userName: userName});
								}
							});
						} else {
							list.push({
								content: _("0bd10a8"),
								callback: function () {
									$rootScope.$broadcast("root:profile", {
										userName: userName,
										isAdd: true,
										event: event
									});
								}
							});
						}
						$scope.contextMenuList = list;
					}
		
					function showMessageContextMenu(actualSenderUserName, msgType,subType, msgId, event) {
						var msg =chatFactory.getMsg(msgId);
		
						if(!msg){
							$scope.isShowContextMenu = false;
							return ;
						}
		
						var mmDigest = msg.MMDigest;
		
		
						var actualSender  = contactFactory.getContact(actualSenderUserName);
						var fromUser = contactFactory.getContact(msg.FromUserName)
		
		
						if(!actualSender || !fromUser ){
							$scope.isShowContextMenu = false;
							return ;
						}
						$scope.contextMenuList = [];
		
						if(!(msg._noSupportMsg && (msg.AppMsgType==confFactory.APPMSGTYPE_TRANSFERS
							||msg.AppMsgType==confFactory.APPMSGTYPE_REALTIME_SHARE_LOCATION
							||msg.AppMsgType==confFactory.APPMSGTYPE_CARD_TICKET
							))){
							if(msg.MMPeerUserName != 'filehelper' && accountFactory.getUserName()==msg.FromUserName && ((Date.now()/1000) - msg.CreateTime) < 2*60){
								$scope.contextMenuList.push({
									content:_("2305051"),
									callback:function () {
										chatFactory.revokemsg(msg)
									}
								});
							}else if(msg.MMPeerUserName != 'filehelper' && accountFactory.getUserName()==msg.FromUserName){
								$scope.contextMenuList.push({
									isDisabled:true,
									content:_("2305051"),
									callback:function () {
		
									}
								});
							}
						}
		
		
		
		
		
		
		
						switch (+msgType) {
							case confFactory.MSGTYPE_TEXT:
		
								var displayName;
								if(fromUser.isRoomContact()){
									displayName=actualSender.getMemberDisplayName(msg.FromUserName) || actualSender.NickName;
								}else{
									displayName=actualSender.NickName;
								}
		
								if(subType == 48){
									/*
									* 后面用文本类型的 “引用” 复制等功能，而 localtion 又是 type=text subtype=48 的奇葩情况，所以这里做例外
									* */
									break;
								}
		
								if(subType && parseInt(subType)){
									$scope.isShowContextMenu = false;
									return;
								}
		
		
		
								   mmDigest = displayName?displayName +':'+msg.MMActualContent:msg.MMActualContent ;
		
		
									mmDigest = mmDigest.replace(':',': ');
		
									$scope.contextMenuList.push({
										content: _("3b61c96"),
										callback: function () {
											var quoteText = [
												_("d9eb6f5"),
												mmDigest,
												_("83b6d34"),
												'<br>—————————<br>'
											].join('')
											$rootScope.$broadcast("root:quoteMsg",quoteText);
										}
									});
		
									if(!confFactory.isClientVersion){
										$scope.contextMenuList.push({
											isCopy: true,
											content: _("79d3abe"),
											callback: function () {
												console.log("复制成功");
												$scope.isShowContextMenu = false;
											},
											copyCallBack: function () {
												var textToCopy = $.Range.current().toString();
												if (textToCopy) {
													return textToCopy;
												} else {
													return getMessageText(event);
												}
											}
										});
									}
		
		
		
		
								event.preventDefault();
								break;
							case confFactory.MSGTYPE_IMAGE:
		
								$scope.contextMenuList.push({
									isDownload: true,
									downloadUrl: confFactory.API_webwxgetmsgimg + '?MsgID=' + msgId + '&skey=' + accountFactory.getSkey(),
									content: _("f26ef91"),
									callback: function () {
										console.log("下载成功");
									}
								});
								event.preventDefault();
								break;
							default:;
		
							   // $scope.isShowContextMenu = false;
						}
		
						/* if(accountFactory.getUserName()==username){
						 $scope.contextMenuList.push({
						 content:_("2305051"),
						 callback:function () {
						 console.log("撤回成功");
						 }
						 });
						 event.preventDefault();
						 $scope.isShowContextMenu = true;
						 }
						 */
						/*$scope.contextMenuList = [{
						 content:_("21e106f"),
						 callback:function () {
						 $rootScope.$broadcast("root:forwardingMsg",userName);
						 }
						 },{
						 content:_("2305051"),
						 callback:function () {
						 $rootScope.$broadcast("root:withdrawMsg",userName);
						 }
						 }];*/
		
						/*
						* 可转发的类型
						* */
						if(((!msg.MMIsAppMsg && (msg.MsgType == confFactory.MSGTYPE_IMAGE
							|| msg.MsgType == confFactory.MSGTYPE_TEXT
							|| msg.MsgType == confFactory.MSGTYPE_VIDEO
							|| msg.MsgType == confFactory.MSGTYPE_MICROVIDEO
							|| msg.MsgType == confFactory.MSGTYPE_LOCATION
							|| msg.MsgType == confFactory.MSGTYPE_EMOTICON
							))
							|| ((msg.MsgType == confFactory.MSGTYPE_APP||msg.MMIsAppMsg) && msg.AppMsgType == confFactory.APPMSGTYPE_ATTACH))&&!msg._noSupportMsg
						  /*  || (msg.MsgType == confFactory.MSGTYPE_APP && msg.AppMsgType == confFactory.APPMSGTYPE_URL)*/
						){
							$scope.contextMenuList.push({
								content:_("21e106f"),
								callback:function () {
									ngDialog.open({
										templateUrl: "transpond.dialog.html",
										controller: "transpondDialogController",
										className: "default transpond-dialog",
										data:{
											msg:msg
										}
									});
								}
							});
		
		
						}
		
		
						$scope.contextMenuList.push({
								content:_("2f4aadd"),
								callback:function () {
									chatFactory.localDelete(msg)
								}
						})
		
		
						if($scope.contextMenuList.length>  0){
							event.preventDefault();
						}else{
							$scope.isShowContextMenu = false;
						}
		
						function getMessageText(event){
							var tgt = event && event.target;
							if (!tgt) return false;
		
							tgt = angular.element(tgt);
							if (!tgt.hasClass("js_message_bubble")) {
								tgt = tgt.parents(".js_message_bubble");
							}
							tgt = tgt.find(".js_message_plain"); // 暂只支持复制文本类消息
		
							if(tgt.length){
								// 后端输出的内容都是编码过得
		
								var originText =tgt.html().replace(new RegExp("<(?!br|" + confFactory.EMOTICON_REG + ").*?>", "g"), ""); // 洗掉各种属性和标签，除了<br>和表情的<img>
								var decode = utilFactory.htmlDecode(originText);
								return   decode; // 洗掉各种属性和标签，除了<br>和表情的<img>
							}else{
								return '';
							}
		
						}
					}
				}]);
		
		})();
	
	
	/***/ }),
	/* 285 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Controllers */
		
		angular.module('Controllers')
			.controller('editAreaContactListController', ['$scope', 'confFactory','utilFactory','$timeout', function ($scope, confFactory, utilFactory,$timeout) {
				var editArea = document.getElementById("editArea"),
					contactPanel = document.getElementById("editAreaContactPanel"),
					caretPosHelper = document.getElementById("caretPosHelper"),
					memberListMaxIndex = $scope.memberList.length - 1;
		
				var ITEM_HEIGTH = 42;
				var SPACE = 10;
		
				function _chooseContact(username, displayname){
					//用input的方式插入
					displayname = utilFactory.clearHtmlStr(displayname) + " ";
					caretPosHelper.innerHTML = displayname;
					var width = caretPosHelper.offsetWidth;
					caretPosHelper.innerHTML = " ";
					$scope.insertContactToEditArea("<input type='text' un='" + username + "' value='" + displayname + "' style='width:" + width + "px' readonly='readonly' />");
		
					//$scope.insertContactToEditArea(displayname + " ");
					$scope.closeThisMmPop();
				}
				function showContact(selectIndex){
					var itemHeigth = ITEM_HEIGTH + SPACE;
					var offsetTop = selectIndex * itemHeigth;
					var scrollTop = contactPanel.scrollTop;
		
					if(scrollTop > offsetTop){
						contactPanel.scrollTop = offsetTop;
						return;
					}
		
					var BottomLimit = offsetTop + itemHeigth + SPACE - contactPanel.offsetHeight;
					if(scrollTop < BottomLimit){
						contactPanel.scrollTop = BottomLimit;
					}
				}
		
		
				$scope.selectIndex = 0;
				setTimeout(function(){
					contactPanel.focus();
				},5);
		
		
				$scope.click = function(e){
					_chooseContact(e.currentTarget.getAttribute("username"), e.currentTarget.getAttribute("displayname"));
				};
				$scope.keydown = function(e){
					switch(e.keyCode){
						case confFactory.KEYCODE_ARROW_UP:
							$scope.selectIndex = --$scope.selectIndex < 0 ? 0 : $scope.selectIndex;
							showContact($scope.selectIndex);
							e.stopPropagation();
							break;
						case confFactory.KEYCODE_ARROW_DOWN:
							$scope.selectIndex = ++$scope.selectIndex > memberListMaxIndex ? memberListMaxIndex : $scope.selectIndex;
							showContact($scope.selectIndex);
							e.stopPropagation();
							break;
						case confFactory.KEYCODE_ENTER:
							var contact = $scope.memberList[$scope.selectIndex];
							if(!contact.getDisplayName) break; // contact对象还没完全建好
		
							_chooseContact(contact.UserName, contact.getDisplayName($scope.chatRoomUserName));
							break;
						default:
							$scope.closeThisMmPop();
							setTimeout(function(){ // the cursor disappears, we need to refocus
								editArea.blur();
								editArea.focus();
							}, 0);
					}
		
					e.preventDefault();
				};
			}]);
		})();
	
	/***/ }),
	/* 286 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Controllers */
		angular.module('Controllers')
		.controller('systemMenuController', [
			'$rootScope',
			'$scope', 
			'$timeout', 
			'ngDialog',
			'loginFactory',
			'confFactory',
			'accountFactory',
			'utilFactory',
			'monitorService',
			'oplogFactory',
			'reportService',
			function($rootScope,$scope, $timeout, ngDialog, loginFactory,confFactory, accountFactory,utilFactory,monitorService,oplogFactory, reportService) {
				
				$scope.createChatroom = function () {
		
					ngDialog.open({
						templateUrl: "createChatroom.html",
						controller: "createChatroomController",
						className:"default create_chatroom_dlg",
						closeByDocument: false,
						data:{
							isCreate:true,
							fromSystemMenu:true
						}
					});
					$scope.closeThisMmPop();
				};
				$scope.loginout = function () {
		
					setTimeout(function() {
						// report session data
						console.time('report');
						var stayTime = new Date().getTime() - accountFactory.getLoginTime();
						reportService.report(reportService.ReportType.sessionData, {
							uin: accountFactory.getUin(),
							browser: navigator.userAgent,
							rmsg: accountFactory.getRMsgCount(),
							rconv: accountFactory.getRConvCount(),
							smsg: accountFactory.getSMsgCount(),
							sconv: accountFactory.getSConvCount(),
							lifetime: stayTime
						}, true);
					}, 0);
					
					setTimeout(function() {
						loginFactory.loginout();
					}, 300);
					
					$scope.closeThisMmPop();
				};
				// 桌面通知
				$scope.isNotifyOpen = accountFactory.isNotifyOpen();
				$scope.closeNotify = function () {
					accountFactory.closeNotify();
					$scope.closeThisMmPop();
				};
				$scope.openNotify = function () {
					accountFactory.openNotify();
					$scope.closeThisMmPop();
				};
		
				// 音效
				$scope.isSoundOpen = accountFactory.isSoundOpen();
				$scope.closeSound = function () {
					accountFactory.closeSound();
					$scope.closeThisMmPop();
				};
				$scope.openSound = function () {
					accountFactory.openSound();
					$scope.closeThisMmPop();
				};
		
				// 意见反馈
				$scope.feedback = function(){
					ngDialog.open({
						templateUrl: "feedback.html",
						controller: ['$scope',function($scope){
							$scope.content = "";
							$scope.send = function(){
								var content = '【新版web微信】【' + navigator.userAgent.toLowerCase() + '】' + $scope.content;
								content = utilFactory.htmlEncode(content);
								oplogFactory.feedback(content);
								$scope.closeThisDialog();
								monitorService.report(monitorService.FEEDBACK_COUNT, 1);
							};
						}],
						className:"default"
					});
					$scope.closeThisMmPop();
				};
				$scope.sendFeedback = function(){
					console.log();
				};
			}
		]);
		})();
	
	/***/ }),
	/* 287 */
	/***/ (function(module, exports) {
	
		/**
		 * Created by jfengjiang on 2015/5/14.
		 */
		
		(function(){
			'use strict';
		
			/* Controllers */
			angular.module('Controllers')
				.controller('readMenuController', [
					'$rootScope',
					'$scope',
					'subscribeMsgService',
					function($rootScope,$scope, subscribeMsgService) {
		
						/**
						 * callback
						 */
						$scope.copyCallback = function () {
							console.log("复制成功");
						};
		
						/**
						 * 复制链接
						 */
						$scope.copyLink = function () {
							console.log(subscribeMsgService.current);
							$scope.closeThisMmPop();
		
							return subscribeMsgService.current && subscribeMsgService.current.Url;
						};
		
						/**
						 * 转发
						 */
						$scope.forwarding = function () {
							$scope.closeThisMmPop();
						};
		
						/**
						 * 新开窗口
						 */
						$scope.openTab = function () {
							var url = subscribeMsgService.current.Url;
							var win = window.open(url, '_blank');
							win.focus();
							$scope.closeThisMmPop();
						}
					}
				]);
		})();
	
	
	/***/ }),
	/* 288 */
	/***/ (function(module, exports) {
	
		(function(){
			'use strict';
		
			/* Controllers */
		
			angular.module('Controllers')
				.controller('transpondDialogController', [
					'$rootScope',
					'$scope',
					'$timeout',
					'$state',
					'$log',
					'$document',
					'chatFactory',
					'contactFactory',
					'appFactory',
					'chatroomFactory',
					'confFactory',
					'mmpop',
					'ngDialog',
					'utilFactory',
					'stateManageService',
					'accountFactory',
					function($rootScope, $scope, $timeout,$state, $log, $document, chatFactory,contactFactory,
							 appFactory, chatroomFactory,confFactory, mmpop, ngDialog, utilFactory,stateManageService,accountFactory) {
		
					   /* var selectorContainer ;
		
						$scope.$watch(function(){
							return $scope.selectedUsers.length;
						},function(len){
							if(len > 15){
								if(!selectorContainer) selectorContainer = $('#createChatRoomContainer .selector')[0];
								setTimeout(function(){
									selectorContainer.scrollTop= 10000;
								},20);
		
							}
						})
		*/
						var msg= $scope.ngDialogData.msg;
						$scope.pickConfig = {
							types:['chatroom','star','friend'],
							opt:{
								star:{
		
								},
								chatroom: {isSaved: true},
								friend:{
									isWithoutStar:true,
									isWithoutBrand:true
								}
							}
						};
		
						var chatList = angular.copy(chatFactory.getChatList());
						chatList.unshift({
							text:_("b3b6735"),
							type:'header'
						});
						$scope.initList = chatList;
		
		
		
		
						$scope.ensure = function(){
		
							var selectedUsers = $scope.selectedUsers;
		
		
							$scope.comfirming = false;
							for(var i= 0; i<selectedUsers.length;i++){
								sendMsg(msg,selectedUsers[i].UserName);
							}
							$scope.closeThisDialog()
						}
						$scope.cancel = function(){
							$scope.comfirming = false;
						}
						$scope.send = function(){
		
							var length = $scope.selectedUsers.length;
		
		
							if(length > 0){
								if(length == 1){
									$scope.ensure();
									return;
								}
		
								if(length > 200){
									alert('选择的人数必须少于200');
									return;
								}
		
								// 少于 1 个则不处理
								$scope.comfirming = true;
							}
						}
		
		
						function sendMsg(msg,to){
		
							if(msg.MsgType == confFactory.MSGTYPE_SYS){
								return;
							}
		
							var transpondMsg = angular.copy(msg) ;
							transpondMsg.ToUserName = to;
							transpondMsg.FromUserName = accountFactory.getUserName();
							transpondMsg.isTranspond = true;
							/*
							* 因为获取 local image 需要 msgid， 但是转发前本地是没有正确的 msgid 的，只能用转发前那个消息的
							* */
							transpondMsg.MsgIdBeforeTranspond = msg.MsgIdBeforeTranspond || msg.MsgId;
		
							transpondMsg._h = undefined;
							transpondMsg._offsetTop = undefined;
							transpondMsg.MMSourceMsgId = msg.MsgId;
		
		
		
		
		
						/*    transpondMsg.Content= msg.OriContent || utilFactory.htmlDecode(transpondMsg.MMActualContent);*/
							transpondMsg.Scene = 2;
							transpondMsg = chatFactory.createMessage(transpondMsg);
		
							/*
							* 文件发送根据这个决定是否 reset 发送状态
							* */
							transpondMsg.sendByLocal =false;
							/*
							 * 地理位置消息有  OriContent
							 * 因为 Content 是阉割过后的
							 * */
							transpondMsg.Content= utilFactory.htmlDecode(transpondMsg.Content.replace(/^@\w+:<br\/>/,''));
							transpondMsg.MMActualSender = accountFactory.getUserName();
							if(transpondMsg.MMSendContent){
								transpondMsg.MMSendContent = transpondMsg.MMSendContent.replace(/^@\w+:\s/,'');
							}
		
							if(transpondMsg.MMDigest){
								transpondMsg.MMDigest = transpondMsg.MMDigest.replace(/^@\w+:/,'');
							}
		
							if(transpondMsg.MMActualContent){
								transpondMsg.MMActualContent = utilFactory.clearHtmlStr(transpondMsg.MMActualContent.replace(/^@\w+:<br\/>/,''));
							}
		
		
							chatFactory.appendMessage(transpondMsg);
							chatFactory.sendMessage(transpondMsg);
						}
		
		
		
					}
				]);
		
		})();
	
	/***/ }),
	/* 289 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('appFactory', 
			['$http', 
			'$q',
			'confFactory',
			'accountFactory', 
			'loginFactory',
			'utilFactory', 
			'reportService',
			'mmHttp',
			function($http, $q, confFactory, accountFactory, loginFactory, utilFactory,reportService,mmHttp) {
		
			var service = {
				globalData:{
					chatList:[]
				},
				/**
				 * 初始化webwxApp
				 */
				init: function () {
					var deferred = $q.defer();
		
		
					mmHttp({
						method:"POST",
						url:confFactory.API_webwxinit,
						MMRetry:{
							count:1,
							timeout:1
						},
						data:{
							BaseRequest:{
								Uin:accountFactory.getUin(),
								Sid:accountFactory.getSid(),
								Skey:accountFactory.getSkey(),
								DeviceID:accountFactory.getDeviceID()
							}
						}
					}).success(function(data){
						deferred.resolve(data);
					}).error(function(data){
						deferred.reject('error:'+data);
					});
					return deferred.promise;
				},
		
				/**
				 * sync获取消息更新具体内容
				 * @return {promise}
				 */
				sync: function () {
					var deferred = $q.defer(),
						that = this;
					// todo:bug
					mmHttp({
						method:"POST",
						MMRetry:{
							serial:true
						},
						url:confFactory.API_webwxsync+'?'+['sid='+accountFactory.getSid(),'skey='+accountFactory.getSkey()].join('&'),
						data:angular.extend(accountFactory.getBaseRequest(),{SyncKey:accountFactory.getSyncKey(), rr:~new Date()})
					}).success(function(data){
						deferred.resolve(data);
		
						if(!utilFactory.getCookie('webwx_data_ticket')){
							reportService.report(reportService.ReportType.cookieError,{
								text:'webwx_data_ticket 票据丢失',
								cookie:document.cookie
							});
						}
		
					}).error(function(data){
						deferred.reject('error:'+data);
						utilFactory.log("sync error");
					});
					return deferred.promise;
				},
		
				/**
				 * syncCheck轮询是否有消息更新
				 * @return {promise}
				 */
				syncCheck: function () {
					var deferred = $q.defer(),
						me = this;
					var url = confFactory.API_synccheck+'?'+[
							'r='+utilFactory.now(),
							'skey='+encodeURIComponent(accountFactory.getSkey()),
							'sid='+encodeURIComponent(accountFactory.getSid()),
							'uin='+accountFactory.getUin(),
							'deviceid='+accountFactory.getDeviceID(),
							'synckey='+encodeURIComponent(accountFactory.getFormateSyncCheckKey())
					].join('&');
		
					window.synccheck && (window.synccheck.selector=0);
					// ie8
					$.ajax({
						url: url,
						dataType : "script",
						timeout : 35000
					}).done(function() {
						if (window.synccheck && window.synccheck.retcode == "0") {
							if (window.synccheck.selector != "0") {
								me.sync().then(function (data) {
									deferred.resolve(data);
								},function (data) {
									console.log('syncCheck sync nothing',data);
		
								});
							}else{
								deferred.reject(window.synccheck && window.synccheck.selector);
							}
						}else if(window.synccheck && (window.synccheck.retcode == "1101" || window.synccheck.retcode == "1102")){
							loginFactory.loginout(1);
							//document.location.reload();
						}else if(window.synccheck && window.synccheck.retcode == "1100"){
							loginFactory.loginout(0);
							//document.location.reload();
						}else{
							deferred.reject('syncCheck net error');
							reportService.report(reportService.ReportType.netError,{
								text:'syncCheck net error',
								url:url
							})
						}
					});
					/*$http.jsonp(url,{
						timeout:35000
					}).success(function (data) {
						console.log('syncCheck success?!',data);
						//not standard jsonp, call error handler.
					}).error(function (data) {
						if (window.synccheck && window.synccheck.retcode == "0") {
							if (window.synccheck.selector != "0") {
								me.sync().then(function (data) {
									deferred.resolve(data);
								},function (data) {
									console.log('syncCheck sync nothing',data);
									deferred.reject('sycn net error');
								});
							}else{
								deferred.reject(window.synccheck && window.synccheck.selector);
							}
						}else if(window.synccheck && (window.synccheck.retcode == "1101" || window.synccheck.retcode == "1102")){
							loginFactory.loginout(1);
							//document.location.reload();
						}else if(window.synccheck && window.synccheck.retcode == "1100"){
							loginFactory.loginout(0);
							//document.location.reload();
						}else{
							deferred.reject('syncCheck net error');
							reportService.report(reportService.ReportType.netError,{
								text:'syncCheck net error',
								url:url
							})
						}
		
					});*/
					return deferred.promise;
				},
				
				/**
				 * 统计
				 */
				report: function (argument) {
					// body...
				}
			};
			return service;
		}]);
		})();
	
	/***/ }),
	/* 290 */
	/***/ (function(module, exports) {
	
		(function(_aoUndefined){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('chatFactory', [
			'$rootScope',
			'$timeout',
			'$http',
			'$q',
			'contactFactory',
			'accountFactory',
			'emojiFactory',
			'confFactory',
			'notificationFactory',
			'utilFactory',
			'reportService',
			'mmHttp',
				'titleRemind',
			function($rootScope,$timeout,$http, $q, contactFactory,accountFactory,emojiFactory, confFactory, notificationFactory, utilFactory,reportService,mmHttp,titleRemind) {
		
			var _chatList = [],
				_chatListInfos = [],
				_chatMessages = window._chatContent = {},
				_currentUserName = '',
				_addedMsgIdsMap = {},
				_msgMap = {};
		
				var _sendFileUserName;
		
				var _currentUnreadMap = {};
		
				var _rChatList = [];
				var _SChatList = [];
		
			var service = {
				setCurrentUserName: function (userName) {
					_currentUserName = userName;
					var currentContact = contactFactory.getContact(userName);
					currentContact._notActive = false;
				},
				/**
				 * 获取当前聊天对象`UserName`
				 * @returns {string}
				 */
				getCurrentUserName: function () {
					return _currentUserName;
				},
				setSendFileUsername:function(userName){
					if(this._sendCheck(userName)){
						_sendFileUserName = userName;
						return true;
					}else{
						return false;
					}
		
		
		
		
				},
				resetSendFileUsername:function(){
					_sendFileUserName = '';
				},
				getSendFileUsername:function(){
					return _sendFileUserName || _currentUserName;
				},
		
				_sendCheck:function(userName){
					var chatCurrentName = $('#chatArea .title_wrap .title_name')[0];
					var navcurrentName = $('#J_NavChatScrollBody')[0];
		
					if(chatCurrentName && navcurrentName){
						var $chatCurrentName = $(chatCurrentName);
						var $navcurrentName = $(navcurrentName);
		
						var chatuser = $chatCurrentName.attr('data-username')
						var navuser = $navcurrentName.attr('data-username')
		
						if(!chatuser || !navuser){
							utilFactory.reportSendState('sendcheckAttrError');
						}
		
						if(!userName){
							utilFactory.reportSendState('toUserNameNotFound');
		
						}
		
		
						if(userName && chatuser == navuser && navuser == userName){
							return true;
						}else{
							/*
							 * todo: 记录错误
							 * */
		
							if(navuser!=userName){
								utilFactory.reportSendState('toUserNameConflictNav');
							}
		
							if(chatuser!=userName){
								utilFactory.reportSendState('toUserNameConflictChat');
							}
		
		
		
		
							utilFactory.reportSendState('uiCheckFail');
							reportService.report(reportService.ReportType.sendError,{
								type:'uiCheckFail',
								browser:utilFactory.browser.msie?'ie':'other',
								values:{
									chatuser:chatuser,
									navuser:navuser,
									userName:userName
								}
							});
		
							return false;
						}
					}else{
		
						if(!chatCurrentName){
							utilFactory.reportSendState('chatCurrentNameNotFound');
						}
		
						if(!navcurrentName){
							utilFactory.reportSendState('navcurrentNameNotFound');
						}
		
						utilFactory.reportSendState('sendcheckElementError');
						return false;
					}
				},
				/**
				 * 创建消息
				 * @param msg 消息体
				 */
				createMessage: function(msg){
					if(!msg.FromUserName) msg.FromUserName = accountFactory.getUserName();
					if(!msg.ToUserName) msg.ToUserName = this.getCurrentUserName();
					msg.ClientMsgId = msg.LocalID = msg.MsgId = (utilFactory.now() + Math.random().toFixed(3)).replace(".", "");
					msg.CreateTime = Math.round(utilFactory.now() / 1000);
					msg.MMStatus = confFactory.MSG_SEND_STATUS_READY;
					msg.sendByLocal = true;
		
		
					switch(msg.MsgType){
						case confFactory.MSGTYPE_TEXT:
							var _atContacts = [];
							msg.Content = msg.Content.replace(/<input.*?un="(.*?)".*?value="(.*?)".*?>/g, function(m, p1, p2){
								_atContacts.push(p1);
								return p2;
							});
							msg.MMAtContacts = _atContacts.join(",");
							msg.MMSendContent = utilFactory.htmlDecode(utilFactory.clearHtmlStr(
								msg.Content
								.replace(/<(?:img|IMG).*?text="(.*?)".*?>/g, function(content, text){ //去img里的text属性替换本身（把img标签(表情)转换成可发送的数据）
										return text.replace(confFactory.MM_EMOTICON_WEB, "");
									})
								.replace(/<(?:br|BR)\/?>/g, "\n")
							)).replace(/<(.*?)>/g, function(str){
								return emojiFactory.EmojiCodeMap[emojiFactory.QQFaceMap[str]] || str;
							});
		
							msg.Content = msg.Content.replace(/<(?!(img|IMG|br|BR))[^>]*>/g, "").replace(/\n/g, "<br>");//把text去掉，展示的时候才不会再匹中emojiFilter
							break;
						case confFactory.MSGTYPE_APP:
							if(msg.AppMsgType==confFactory.APPMSGTYPE_URL){
								/*
								 * 转发图文消息特殊处理
								 * */
								break
							}
		
							msg.AppMsgType = confFactory.APPMSGTYPE_ATTACH;
							msg.Content =
								"<msg><appmsg appid='wxeb7ec651dd0aefa9' sdkver=''>"+
									"<title>" + msg.FileName + "</title>" +
									"<des></des>"+
									"<action></action>"+
									"<type>" + confFactory.APPMSGTYPE_ATTACH + "</type>"+
									"<content></content>"+
									"<url></url>"+
									"<lowurl></lowurl>"+
									"<appattach>"+
										"<totallen>" + msg.FileSize + "</totallen>"+
										"<attachid>#MediaId#</attachid>"+ //MediaId在上传成功后调用sendAppMessage时更新
										"<fileext>" + (msg.MMFileExt||msg.MMAppMsgFileExt) + "</fileext>"+
									"</appattach>"+
									"<extinfo></extinfo>"+
								"</appmsg></msg>";
						   // msg.MediaId = "#MediaId#";
							break;
					}
		
					return msg;
				},
				/**
				 * 添加消息到消息库（并且展示消息）
				 * @param msg
				 */
				appendMessage: function(msg){
					msg.MMStatus = confFactory.MSG_SEND_STATUS_SENDING;
					this.messageProcess(msg);
				},
				/**
				 * 发送消息（触发sendmsgAPI）
				 * @param msg
				 */
				sendMessage: function(msg){
					msg.MMStatus = confFactory.MSG_SEND_STATUS_SENDING;
					switch(msg.MsgType){
						case confFactory.MSGTYPE_TEXT:
							this.postTextMessage(msg);
							break;
						case confFactory.MSGTYPE_IMAGE:
							this.postImgMessage(msg);
							break;
						case confFactory.MSGTYPE_MICROVIDEO:
							this.postMicroVideoMessage(msg);
							break;
		
						/* 小视屏 */
						case confFactory.MSGTYPE_VIDEO:
							this.postVideoMessage(msg);
							break;
		
						case confFactory.MSGTYPE_APP:
							this.postAppMessage(msg);
							break;
						case confFactory.MSGTYPE_EMOTICON:
							this.postEmoticonMessage(msg);
					}
		
					// 记录发消息次数
					accountFactory.setSMsgCount(accountFactory.getSMsgCount() + 1);
		
					// 记录发消息会话数
					var index = _SChatList.indexOf(msg.ToUserName);
					if (index === -1) {
						accountFactory.setSConvCount(accountFactory.getSConvCount() + 1);
						_SChatList.push(msg.ToUserName);
					}
				},
		
				/**
				 * 发消息到服务器
				 * @param data 需要带上的数据
				 * @param msg 消息本身，用于发送成功后改变它的状态等
				 * @private
				 */
				_postMessage: function(url, data, msg){
					data.FromUserName = msg.FromUserName;
					data.ToUserName = msg.ToUserName;
					data.LocalID = msg.LocalID;
					data.ClientMsgId = msg.ClientMsgId;
					data = angular.extend(accountFactory.getBaseRequest(), {Msg: data});
		
					data.Scene = msg.Scene || 0;
		
					// 调用angularjs的$http发请求会经过JSON.stringify来处理data，而IE8下中文会变成unicode，所以这里先做字符串转换
					if(utilFactory.browser.msie && parseInt(utilFactory.browser.version) < 9 && url == confFactory.API_webwxsendmsg) data = eval("'" + JSON.stringify(data) + "'");
		
					mmHttp({
						method: "POST",
						url: url,
						data: data,
						MMRetry:{
							serial:true
						}
					}).success(function (data) {
						if(data.BaseResponse.Ret == 0){
							msg.MsgId = data.MsgID;
							_msgMap[msg.MsgId] = msg;
							_addedMsgIdsMap[msg.MsgId]= true;msg.MMStatus = confFactory.MSG_SEND_STATUS_SUCC;
		
							$rootScope.$broadcast('root:msgSend:success',msg);
						}else{
							reportService.report(reportService.ReportType.netError,{
								text:'postMessage error',
								url:url,
								res:data
							})
							//console.log('chatSender error, ret:' + data.BaseResponse.Ret);
							msg.MMStatus = confFactory.MSG_SEND_STATUS_FAIL;
						}
					}).error(function (data) {
						reportService.report(reportService.ReportType.netError,{
							text:'postMessage error',
							url:url,
							res:data
						})
		
						msg.MMStatus = confFactory.MSG_SEND_STATUS_FAIL;
					});
				},
				// 发送纯文本消息
				postTextMessage: function (msg) {
					var data = {
						Type: confFactory.MSGTYPE_TEXT,
						Content: msg.MMSendContent
					};
					if(msg.MMAtContacts&& msg.MMAtContacts.length){
						data.MsgSource =
							"<msgsource>" +
								"<atusername>" + msg.MMAtContacts + "</atusername>" +
								"<atchatroomname>" + msg.ToUserName + "</atchatroomname>" +
							"</msgsource>";
					}
		
		
					/*
					* 发送 localtion 消息的特殊处理，主要用于转发
					* */
					if(msg.SubMsgType == confFactory.MSGTYPE_LOCATION){
						data.Type  = confFactory.MSGTYPE_LOCATION;
						data.Content = msg.OriContent;
					}
		
					this._postMessage(confFactory.API_webwxsendmsg, data, msg);
				},
				// 发送图片消息
				postImgMessage: function(msg){
					var data = {
						Type: confFactory.MSGTYPE_IMAGE,//兼容后台而带上Type
						MediaId: msg.MediaId,
						Content:msg.Content
					};
					this._postMessage(confFactory.API_webwxsendmsgimg + "?fun=async&f=json", data, msg);
				},
				// 发送视频消息
				postVideoMessage: function(msg){
					var data = {
						Type: confFactory.MSGTYPE_VIDEO,//兼容后台而带上Type
						MediaId: msg.MediaId,
						Content:msg.Content
					};
					this._postMessage(confFactory.API_webwxsendmsgvedio + "?fun=async&f=json", data, msg);
				},
		
				// 发送小视频消息
				postMicroVideoMessage: function(msg){
					var data = {
						Type: confFactory.MSGTYPE_MICROVIDEO,//兼容后台而带上Type
						MediaId: msg.MediaId,
						Content:msg.Content
					};
					this._postMessage(confFactory.API_webwxsendmsgvedio + "?fun=async&f=json", data, msg);
				},
		
		
		
				// 发送APP消息，目前只支持发文件
				postAppMessage: function(msg){
					var data;
					data = {
						Signature:msg.Signature,
						/*
						 *  当可以发其他 app 消息，比如图文链接的时候就有问题
						 * */
						Type: msg.AppMsgType ,//兼容后台而带上Type
		
					};
					if(msg.AppMsgType == confFactory.APPMSGTYPE_ATTACH){
						var appid = confFactory.isClientVersion?'':'wxeb7ec651dd0aefa9';
							data.Content=  "<appmsg appid='"+appid+"' sdkver=''>"+
								"<title>" + msg.FileName + "</title>" +
								"<des></des>"+
								"<action></action>"+
								"<type>" + confFactory.APPMSGTYPE_ATTACH + "</type>"+
								"<content></content>"+
								"<url></url>"+
								"<lowurl></lowurl>"+
								"<appattach>"+
								"<totallen>" + msg.FileSize + "</totallen>"+
								"<attachid>" + msg.MediaId + "</attachid>"+
								"<fileext>" + (msg.MMFileExt||msg.MMAppMsgFileExt) + "</fileext>"+
								"</appattach>"+
								"<extinfo>"+
								"</extinfo>"+
								"</appmsg>";
					}else{
							data.Content = msg.OriContent || msg.Content;
					}
		
		
					this._postMessage(confFactory.API_webwxsendappmsg + "?fun=async&f=json"+(confFactory.isClientVersion?'&mod=desktop':''), data, msg);
				},
				// 发送表情消息
				postEmoticonMessage: function(msg){
					var data = {
						Type: confFactory.MSGTYPE_EMOTICON, // 兼容后台而带上Type
						EmojiFlag : msg.EmojiFlag,
						EMoticonMd5 : msg.EMoticonMd5||msg.md5
					};
					if(msg.MediaId ) data.MediaId = msg.MediaId;
		
					if(msg.MMSourceMsgId && (typeof msg.MMStatus != 'undefined') && msg.MMStatus!=confFactory.MSG_SEND_STATUS_SUCC){
						msg.MMPreviewSrc = confFactory.API_webwxgetmsgimg + '?'+'&MsgID='+ msg.MMSourceMsgId +'&skey=' + encodeURIComponent(accountFactory.getSkey()) + '&type=big';
					}
					this._postMessage(confFactory.API_webwxsendemoticon + "?fun=sys", data, msg);
				},
		
				initChatList: function (userNames) {
					var me = this,
						userNamesList = userNames.split(",");
					angular.forEach(userNamesList,function (userName,key) {
						if(!userName || utilFactory.isShieldUser(userName) || utilFactory.isSpUser(userName)) return;
						var index = _chatList.indexOf(userName);
						if(index == -1){
							_chatList.push(userName);
							if(utilFactory.isRoomContact(userName)){
								contactFactory.addBatchgetChatroomContact(userName);
								//contactFactory.batchGetChatroomMembersContact(userName);
							}
						}
					});
					//updat chatlistInfos
					me.getChatList();
				},
				/**
				 * 添加聊天列表用户
				 */
				addChatList : function(list) {
					var me = this;
		
					if(!list) return;
					if(!angular.isArray(list)) list = [list];
		
					angular.forEach(list,function (item,key) {
						var tmpUserName = '',
							tmpUserNameIndex = 0;
		
						if(item.UserName){
							tmpUserName = item.UserName;
						}else if(item.FromUserName == accountFactory.getUserInfo().UserName){
							tmpUserName = item.ToUserName;
						}else{
							tmpUserName = item.FromUserName;
						}
						tmpUserNameIndex = _chatList.indexOf(tmpUserName);
						if(tmpUserNameIndex==-1){
							_chatList.unshift(tmpUserName);
		
							if(utilFactory.isRoomContact(tmpUserName)){
								contactFactory.addBatchgetChatroomContact(tmpUserName);
								//contactFactory.batchGetChatroomMembersContact(tmpUserName);
							}
						}else{
							var currentItem = _chatList.splice(tmpUserNameIndex,1);
							_chatList.unshift(currentItem[0]);
						}
					});
					//updat chatlistInfos
					me.getChatList();
					$rootScope.$broadcast('chat:add:success');
				},
				/**
				 * 删除聊天列表用户
				 */
				deleteChatList: function (list) {
					var me = this;
		
					if(!list) return;
					if(!angular.isArray(list)) list = [list];
		
					angular.forEach(list,function (userName,key) {
						var index = _chatList.indexOf(userName);
						if(index > -1){
							_chatList.splice(index,1);
						}
					});
					//updat chatlistInfos
					me.getChatList();
				},
				/**
				 * 获取聊天列表用户
				 */
				getChatList : function() {
					var me = this,tmp=[];
					_chatListInfos.length = 0;
					angular.forEach(_chatList,function (userName,key) {
						var contactItem = contactFactory.getContact(userName),
							lastMessage,
							chatListItem = {};
						// 公众号和特殊屏蔽号都不会出现在列表里面
						if(contactItem && !contactItem.isBrandContact() && !contactItem.isShieldUser()){
							if(userName == _currentUserName){
								//console.log('getChatList markMsgsRead');
		
								var currentUnreadCount = me.getUnreadMsgsCount(userName);
		
								if(!contactItem.unreadCount || contactItem.unreadCount <  currentUnreadCount){
									contactItem.unreadCount = me.getUnreadMsgsCount(userName);
								}
		
		
								if(!contactItem._notActive){
								  if(me.markMsgsRead(userName)){
									me.notifyMobile(userName,confFactory.StatusNotifyCode_READED);
								  }
								}
							}
							lastMessage = me._getLastMessage(contactItem.UserName);
							angular.extend(chatListItem,contactItem,{
								MMDigest: lastMessage.MMDigest || '',
								NoticeCount: me.getUnreadMsgsCount(userName),
								MMStatus: lastMessage.MMStatus,
								MMTime: lastMessage.MMTime || '',
								MMDigestTime: lastMessage.MMDigestTime || ''
							});
							tmp.push(chatListItem);
						}
					});
					//console.log('chatlist',_chatListInfos)
					[].push.apply(_chatListInfos,handleChatList(tmp));
					return _chatListInfos;
				},
				/**
				 * 获取用户最后的消息
				 */
				_getLastMessage: function (userName) {
					var me = this,
						messages = me.getChatMessage(userName);
		
					if(messages.length){
						return messages[messages.length-1];
					}else{
						return {};
					}
				},
				/**
				 * 添加聊天用户内容
				 */
				addChatMessage: function (message) {
					if (!message) {return;}
		
					var me = this,
						fromUserName = message.FromUserName,
						toUserName = message.ToUserName,
						userMessages = _chatMessages[message.MMPeerUserName] || (_chatMessages[message.MMPeerUserName] = []);
		
					//过滤已处理信息
					if(_addedMsgIdsMap[message.MsgId]) return;
					_addedMsgIdsMap[message.MsgId] = true;
					_msgMap[message.MsgId] = message;
		
					//console.log("msgid=" + message.MsgId);
					userMessages.push(message);
					$rootScope.$broadcast('message:add:success',message);
		
		
					//updat chatlistInfos
					me.getChatList();
				},
				getMsg:function(msgId){
					return _msgMap[msgId];
				},
				deleteChatMessage: function (userName) {
					_chatMessages[userName] = [];
				},
				updateChatMessage:function (message) {
					// body...
				},
				showMessage : function(_displayName, _oMessage, _anInsertPos) {
					if (_displayName) {
						_oMessage.DisplayName = _displayName;
					} else {
						var _oActualSender = contactFactory.getContact(_oMessage.MMActualSender);
						if(_oActualSender && _oActualSender.DisplayName){
							_oMessage.DisplayName = _oActualSender.DisplayName;
						} else {
							_oMessage.DisplayName = _oMessage.MMActualSender;
						}
					}
					//_aoWebMM.triggerEvent(_anInsertPos===_aoUndefined ? "messageAdded" : "messagePrepend", _oMessage);
				},
				updateMessage : function(userMessages, index, message){
					angular.extend(userMessages[index], message);
				},
				/**
				 * 根据`username`，获取聊天用户内容
				 * @param userName
				 * @param clearNoticeCount
				 * @returns {Array} 聊天内容集合
				 */
				getChatMessage: function (userName,clearNoticeCount) {
					var me = this;
					if(clearNoticeCount){
						_currentUserName = userName;
						me.markMsgsRead(userName);
					}
					if(!_chatMessages[userName]) {
						//不直接返回空数组：return [];
						//保存引用，angular才能自动更新
						_chatMessages[userName] = [];
					}
					return _chatMessages[userName];
				},
				cleanChatMessage: function (userName) {
					if(_chatMessages[userName]){
						_chatMessages[userName].splice(0,_chatMessages[userName].length);
					}
				},
				/**
				 * 获取聊天用户内容
				 */
				getChatMessageBySlice: function (userName,index,count) {
					var me = this;
					//if(clearNoticeCount){
						_currentUserName = userName;
						me.clearChatNoticeCount();
					//}
					if(_chatMessages[userName]) {
						return _chatMessages[userName].slice(index,count);
					} else {
						return [];
					}
				},
		
		
				setCurrentUnread:function(username,count){
					_currentUnreadMap[username] = count;
				},
		
		
		
				/**
				 * 获取用户未读消息数
				 * @param userName
				 */
				getUnreadMsgsCount : function(userName){
					var unreadCout = 0,
						messages;
		
				   // if(unreadCout > 99) return "99+";
					if(_currentUnreadMap[userName]){
						return _currentUnreadMap[userName];
					} else{
					  if (messages = _chatMessages[userName]){
						for (var i=messages.length-1; i>=0; i--){
						  if (messages[i].MMUnread) {
							++unreadCout;
						  }
						}
					  }
		
		
					  return unreadCout;
					}
		
		
				},
				/**
				 * 标记用户消息为已读
				 * @param userName
				 */
				markMsgsRead : function(userName){
					var messages = this.getChatMessage(userName),
						hasUnreaded = false;
					for (var i=0,len=messages.length; i<len; i++){
						if (messages[i].MMUnread) {
							hasUnreaded = true;
						}
						messages[i].MMUnread = false;
					}
		
					this.setCurrentUnread(userName,0);
					return hasUnreaded;
				},
				/**
				 * 消息处理入口
				 * @param message 消息体
				 */
				messageProcess: function (message) {
					var me = this;
					var fromUser = contactFactory.getContact(message.FromUserName,'',true);
					// 屏蔽，自己，不应该显示，品牌商家，这四种不提示
					if(fromUser && !fromUser.isMuted() && !fromUser.isSelf() && !fromUser.isShieldUser() && !fromUser.isBrandContact()){
						titleRemind.increaseUnreadMsgNum();
					}
					message.MMPeerUserName = me._getMessagePeerUserName(message);
		
					if(message.MsgType == confFactory.MSGTYPE_STATUSNOTIFY){
						me._statusNotifyProcessor(message);
						return;
					}else if(message.MsgType == confFactory.MSGTYPE_SYSNOTICE){
						console.log('MSGTYPE_SYSNOTICE',message.Content);
						return;
					}
		
					if (utilFactory.isShieldUser(message.FromUserName) || utilFactory.isShieldUser(message.ToUserName)
						|| (message.MsgType == confFactory.MSGTYPE_VERIFYMSG && message.RecommendInfo
							&& message.RecommendInfo.UserName == accountFactory.getUserInfo().UserName)
						) {
						return;
					}
		
					me._commonMsgProcess(message);
					switch(message.MsgType){
						case confFactory.MSGTYPE_APP://APP消息
							try{
								message.MMIsAppMsg = true;
								me._appMsgProcess(message);
							}catch(e){console.log('catch _appMsgProcess error', e, message)}
							break;
						case confFactory.MSGTYPE_EMOTICON://表情消息
							me._emojiMsgProcess(message);
							break;
						case confFactory.MSGTYPE_IMAGE://图片消息
							me._imageMsgProcess(message);
							break;
						case confFactory.MSGTYPE_VOICE://语音消息
							me._voiceMsgProcess(message);
							break;
						case confFactory.MSGTYPE_VIDEO://视频消息
							me._videoMsgProcess(message);
							break;
						case confFactory.MSGTYPE_MICROVIDEO://小视频消息
							me._mircovideoMsgProcess(message);
							break;
						case confFactory.MSGTYPE_TEXT://文本消息
							if(message.FromUserName == "newsapp") {
								me._newsMsgProcess(message);
							}else if(message.AppMsgType == confFactory.APPMSGTYPE_RED_ENVELOPES){
								// 将红包消息的MsgType改为MSGTYPE_APP
								message.MsgType = confFactory.MSGTYPE_APP;
								me._appMsgProcess(message);
							}else if(message.SubMsgType == confFactory.MSGTYPE_LOCATION){
								me._locationMsgProcess(message);
							}
							else{
								me._textMsgProcess(message);
							}
							break;
						case confFactory.MSGTYPE_RECALLED://消息撤回
							me._recalledMsgProcess(message);
							//直接返回
							return;
							break;
						case confFactory.MSGTYPE_LOCATION://地理位置消息
							me._locationMsgProcess(message);
							break;
						case confFactory.MSGTYPE_VOIPMSG://VOIP消息
						case confFactory.MSGTYPE_VOIPNOTIFY:
						case confFactory.MSGTYPE_VOIPINVITE:
							me._voipMsgProcess(message);
							break;
						case confFactory.MSGTYPE_POSSIBLEFRIEND_MSG://好友推荐消息
							me._recommendMsgProcess(message);
							break;
						case confFactory.MSGTYPE_VERIFYMSG://认证消息
							me._verifyMsgProcess(message);
							break;
						case confFactory.MSGTYPE_SHARECARD://名片消息
							me._shareCardProcess(message);
							break;
						case confFactory.MSGTYPE_SYS://系统消息
							me._systemMsgProcess(message);
							break;
						default:
							message.MMDigest = confFactory.isClientVersion?'暂不支持该消息':_("938b111");
					}
					message.MMActualContent = utilFactory.hrefEncode(message.MMActualContent);
					//message.MMIsSend && me.markMsgsRead(message.MMPeerUserName);
		
					// notify && sound
					var contact = contactFactory.getContact(message.MMPeerUserName);
					if(!message.MMIsSend
						&& (!contact || (!contact.isMuted()&&!contact.isBrandContact()))
						&& (message.MsgType != confFactory.MSGTYPE_SYS)){
						if(accountFactory.isNotifyOpen()) me._notify(message);
						if(accountFactory.isSoundOpen()) utilFactory.initMsgNoticePlayer(confFactory.RES_SOUND_RECEIVE_MSG);
					}
		
					me.addChatMessage(message);
					me.addChatList([message]);
				},
				/**
				 * 状态通知消息处理
				 * @param message 消息体
				 * @private
				 */
				_statusNotifyProcessor: function (message) {
					var me = this;
					switch(message.StatusNotifyCode){
						case confFactory.StatusNotifyCode_SYNC_CONV://同步会话列表
							me.initChatList(message.StatusNotifyUserName);
							break;
						case confFactory.StatusNotifyCode_ENTER_SESSION://进入会话
							me.markMsgsRead(message.MMPeerUserName);
							me.addChatList([message]);
							break;
						case confFactory.StatusNotifyCode_QUIT_SESSION://退出会话
							// do nothing
							break;
					}
				},
				/**
				 * 通用消息处理
				 * @param message 消息体
				 * @private
				 */
				_commonMsgProcess: function (message) {
					var me = this,index,userContact,
						actualContent = '',
						actualSender = '',
						userMessages,
						displayName = '';
		
					message.Content = message.Content || '';
					message.MMDigest = '';
					message.MMIsSend = (message.FromUserName == accountFactory.getUserName() || message.FromUserName == "");
					//message.MMPeerUserName = me._getMessagePeerUserName(message);
					userMessages = me.getChatMessage(message.MMPeerUserName);
					if(utilFactory.isRoomContact(message.MMPeerUserName)) {
						message.MMIsChatRoom = true;
						actualContent = message.Content.replace(/^(@[a-zA-Z0-9]+|[a-zA-Z0-9_-]+):<br\/>/,function(str,userName){
							actualSender = userName;
							return '';
						});
						if(actualSender && actualSender != accountFactory.getUserName()){
							userContact = contactFactory.getContact(actualSender,message.MMPeerUserName);
							if(userContact){
								displayName = userContact.getDisplayName(message.MMPeerUserName);
								displayName && (message.MMDigest = displayName + ':');
							}
						}
						/*if(index < 0 || message.MMIsSend){ // 自己发送的消息也有可能带:<br/>，如发送地理位置的消息
							actualContent = message.Content;
						}else{
							actualSender = message.Content.substr(0,index);
							actualContent = message.Content.substr(index + 6);
							userContact = contactFactory.getContact(actualSender,message.MMPeerUserName);
							if(userContact){
								displayName = userContact.getDisplayName(message.MMPeerUserName);
								displayName && (message.MMDigest = displayName + ':');
							}
						}*/
					} else {
						message.MMIsChatRoom = false;
						actualContent = message.Content;
					}
					if(!message.MMIsSend
						&& message.MMUnread == _aoUndefined
						&& message.MsgType != confFactory.MSGTYPE_SYS) {
						message.MMUnread = true;
					}
					if (!message.LocalID) {
						message.ClientMsgId = message.LocalID = message.MsgId;
					}
					actualContent = emojiFactory.emoticonFormat(actualContent);
					message.MMActualContent = actualContent;
					message.MMActualSender = actualSender || message.FromUserName;
					me._calcMsgDisplayTime(userMessages[userMessages.length-1],message);
				},
				/**
				 * 文本消息处理
				 * @param message 消息体
				 * @private
				 */
				_textMsgProcess: function (message) {
					message.MsgType = confFactory.MSGTYPE_TEXT;
					message.MMDigest += message.MMActualContent.replace(/<br ?[^><]*\/?>/g,'');;
				},
				/**
				 * 图片消息处理
				 * @param message 消息体
				 * @private
				 */
				_imageMsgProcess: function (message) {
					message.MsgType = confFactory.MSGTYPE_IMAGE;
					message.MMDigest += _("a5627e8");
				},
				/**
				 * 语音消息处理
				 * @param message 消息体
				 * @private
				 */
				_voiceMsgProcess: function (message) {
					message.MsgType = confFactory.MSGTYPE_VOICE;
					message.MMDigest += _("b28dac0");
					message.MMVoiceUnRead = !message.MMIsSend && message.MMUnread; // 如果语音有别人发出并且未读
				},
				/**
				 * 视频消息处理
				 * @param message 消息体
				 * @private
				 */
				_videoMsgProcess: function (message) {
					message.MsgType = confFactory.MSGTYPE_VIDEO;
					message.MMDigest += _("4078104");
				},
				/**
				 * 小视频消息处理
				 * @param message 消息体
				 * @private
				 */
				_mircovideoMsgProcess: function (message) {
					message.MsgType = confFactory.MSGTYPE_MICROVIDEO;
					message.MMDigest += _("1f94b1b");
				},
				/**
				 * news消息处理
				 * @param message 消息体
				 * @private
				 */
				_newsMsgProcess: function (message) {
					var content = utilFactory.htmlDecode(message.MMActualContent).replace(/<br\/>/g,'');
					content = utilFactory.encodeEmoji(content);
					content = utilFactory.xml2json(content);
					message.MMCategory = content && content.category;
				},
				/**
				 * emoji消息处理
				 * @param message 消息体
				 * @private
				 */
				_emojiMsgProcess : function(message) {
					var me = this;
					//商业表情转为文本提示
					if(message.HasProductId){
						if(message.MMIsSend){
							message.MMActualContent = ''+_("80f56fb");
						}else{
							message.MMActualContent = _("2242ac7") + '';
						}
		
						message._noSupportMsg = true;
						me._textMsgProcess(message);
					}else{
						message.MsgType = confFactory.MSGTYPE_EMOTICON;
						var xmlMsg = utilFactory.xml2json(utilFactory.htmlDecode(message.MMActualContent))
						if(xmlMsg && xmlMsg.emoji && xmlMsg.emoji.md5){
							message.md5 = xmlMsg.emoji.md5;
						}
						message.MMDigest += _("e230fc1");
					}
		
				  //  var content = utilFactory.xml2json(message.content);
				},
				/**
				 * voip消息处理
				 * @param message 消息体
				 * @private
				 */
				_voipMsgProcess: function (message) {
					this._appAsTextMsgProcess(message, _("fdaa3a3"));
				},
				/**
				 * 地理位置消息处理
				 * @param message 消息体
				 * @private
				 */
				_locationMsgProcess: function (message) {
					var d = message.Content.split(':<br/>');
					if (d[2]){
						message.MMLocationDesc = d[1];
						// 现在有单独的字段`Url`标识跳转的链接，不用苦逼从content取了
						message.MMLocationUrl = d[2];
					}else{
						message.MMLocationDesc = d[0];
						message.MMLocationUrl = d[1];
					}
					message.MMLocationUrl = message.Url || message.MMLocationUrl;
					message.MMDigest += message.MMLocationDesc;
					//this._appAsTextMsgProcess(message, _("2cc0cfc"));
				},
				/**
				 * app消息处理
				 * @param message 消息体
				 * @private
				 */
				_appMsgProcess: function (message) {
					var me = this;
					switch(message.AppMsgType){
						case confFactory.APPMSGTYPE_TEXT:
							me._appTextMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_IMG:
							me._imageMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_AUDIO:
							me._appAudioMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_VIDEO:
							me._appVideoMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_EMOJI:
							me._emojiMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_URL:
							me._appUrlMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_ATTACH:
							me._appAttachMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_TRANSFERS:
							me._appTransfersMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_RED_ENVELOPES:
							me._appRedEnvelopesMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_CARD_TICKET:
							me._appCardTicketMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_OPEN:
							me._appOpenMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_REALTIME_SHARE_LOCATION:
							me._appRealtimeShareLocationMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_SCAN_GOOD:
							me._appScanGoodMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_GOOD:
							me._appGoodMsgProcess(message);
							break;
						case confFactory.APPMSGTYPE_EMOTION:
							me._appEmotionMsgProcess(message);
							break;
						default:
							me._appUnknowMsgProcess(message);
					}
				},
				/**
				 * app文本消息
				 * @param  {[type]} message
				 */
				_appTextMsgProcess: function (message) {
					var me = this,
						content = utilFactory.htmlDecode(message.MMActualContent).replace(/<br\/>/g,'');
		
					content = utilFactory.encodeEmoji(content);
					content = utilFactory.xml2json(content);
					this._appAsTextMsgProcess(message, utilFactory.decodeEmoji(utilFactory.htmlEncode(content.appmsg.title)));
				},
				/**
				 * app语音消息
				 * @param  {[type]} message
				 */
				_appAudioMsgProcess: function (message) {
					var me = this,
						digest = _("0e23719") + message.FileName;
		
					me._appUrlMsgProcess(message,digest);
				},
				/**
				 * app视频消息
				 * @param  {[type]} message
				 */
				_appVideoMsgProcess: function (message) {
					var me = this,
						digest = _("4078104") + message.FileName;
		
					me._appUrlMsgProcess(message,digest);
				},
				/**
				 * app应用消息
				 * @param  {[type]} message
				 */
				_appOpenMsgProcess: function (message) {
					var me = this,
						digest = _("4f20785");
		
					me._appUrlMsgProcess(message,digest);
					message.MMAlert = _("c4e04ee");
				},
				/**
				 * app链接消息
				 * @param  {[type]} message
				 * @param  {[type]} digest
				 */
				_appUrlMsgProcess: function (message,digest) {
					message.MsgType = confFactory.MSGTYPE_APP;
					message.AppMsgType = confFactory.APPMSGTYPE_URL;
					digest = digest || _("e5b228c") + message.FileName;
		
					var content = utilFactory.htmlDecode(message.MMActualContent).replace(/<br\/>/g,'');
					content = utilFactory.encodeEmoji(content);
					content = utilFactory.xml2json(content);
					//message.MMAppMsgTitle = content.appmsg.title;
					message.MMAppMsgDesc = utilFactory.decodeEmoji(content.appmsg.des);
					//message.MMAppMsgUrl = content.appmsg.url;
					message.MMDigest += digest;
					if(content.appmsg.mmreader){
						this._appReaderMsgProcess(message,content.appmsg.mmreader);
					}
				},
				_appReaderMsgProcess: function(message,readerObj){
					message.MsgType = confFactory.MSGTYPE_APP;
					message.AppMsgType = confFactory.APPMSGTYPE_READER_TYPE;
					if(readerObj.category.count == 1){
						message.MMCategory = [readerObj.category.item];
					}else{
						message.MMCategory = readerObj.category.item;
					}
					angular.forEach(message.MMCategory, function (item) {
						var pub_time = new Date(item.pub_time*1000);
						item.pub_time = utilFactory.formatNum(pub_time.getMonth()+1,2) + "-" + utilFactory.formatNum(pub_time.getDate(), 2);
						var segs = item.cover.split("|");
						if (segs.length == 3) {
							item.cover = segs[0];
							item.width = segs[1];
							item.height = segs[2];
						}
					});
					message.MMDigest += message.MMCategory.length && message.MMCategory[0].title;
				},
				/**
				 * app附件消息
				 * @param  {[type]} message
				 */
				_appAttachMsgProcess: function (message) {
					var content = utilFactory.htmlDecode(message.MMActualContent).replace(/<br\/>/g,'');
					content = utilFactory.encodeEmoji(content);
					content = utilFactory.xml2json(content);
		
					//console.log(content);
					message.MMDigest += _("6daeae3");
					if(message.sendByLocal){
						message.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_SENDING;
					}else{
						message.MMFileStatus = confFactory.MM_SEND_FILE_STATUS_SUCCESS;
					}
		
					message.MMAppMsgFileExt = content.appmsg.appattach.fileext.toLowerCase();
					message.MMAppMsgFileSize = utilFactory.getSize(+content.appmsg.appattach.totallen);
					message.MMAppMsgDownloadUrl = confFactory.API_webwxdownloadmedia +
												  '?sender='+ message.FromUserName +
												  '&mediaid=' + message.MediaId +
												  '&encryfilename=' + message.EncryFileName +
												  '&fromuser=' + accountFactory.getUin()+
												   '&pass_ticket=' + encodeURIComponent(accountFactory.getPassticket())+
													"&webwx_data_ticket="+encodeURIComponent(utilFactory.getCookie('webwx_data_ticket'));
				},
				/**
				 * app转账消息
				 * @param  {[type]} message
				 */
				_appTransfersMsgProcess: function (message) {
					this._appAsTextMsgProcess(message, _("0cdad09"));
				},
				/**
				 * app卡券消息
				 * @param  {[type]} message
				 */
				_appCardTicketMsgProcess: function (message) {
					this._appAsTextMsgProcess(message, _("c534fc3"));
				},
				/**
				 * app共享实时位置消息处理
				 * @param message 消息体
				 * @private
				 */
				_appRealtimeShareLocationMsgProcess: function (message) {
					var content = "";
					if(message.FromUserName == accountFactory.getUserName()){
						content = "[" + _("8e94ca5") + "]";
					}else{
						var displayName;
						var contact = contactFactory.getContact(message.MMActualSender);
						if(contact){
							displayName = contact.getDisplayName(utilFactory.isRoomContact(message.FromUserName) ? message.FromUserName : null);
						}
						content = "[" + (displayName ? displayName : _("a41d576")) + _("a1f1299") + "]";
					}
					this._appAsTextMsgProcess(message, content);
				},
				/**
				 * app扫商品消息处理
				 * @param message 消息体
				 * @private
				 */
				_appScanGoodMsgProcess: function (message) {
					this._appAsTextMsgProcess(message, _("95afe20"));
				},
				/**
				 * app商品消息处理
				 * @param message 消息体
				 * @private
				 */
				_appGoodMsgProcess: function (message) {
					this._appAsTextMsgProcess(message, _("355765a"));
				},
				/**
				 * app表情分享消息处理
				 * @param message 消息体
				 * @private
				 */
				_appEmotionMsgProcess: function (message) {
					this._appAsTextMsgProcess(message, _("9d7f4bb"));
				},
				_appRedEnvelopesMsgProcess: function (message) {
					message.MMDigest += _("e24e75c");
					//this._appAsTextMsgProcess(message, _("c5e6ab0"));
				},
				/**
				 * app未知消息，用于调试
				 * @param  {[type]} message
				 */
				_appUnknowMsgProcess: function (message) {
					if(confFactory.isClientVersion){
						this._appAsTextMsgProcess(message, '[收到一条暂不支持的消息类型，请在手机上查看]');
					}else{
						this._appAsTextMsgProcess(message, '[收到一条网页版微信暂不支持的消息类型，请在手机上查看]');
					}
		
				},
				/**
				 * 将网页不支持的APP消息 以 文本方式 展现
				 * @param message 消息体
				 * @private
				 */
				_appAsTextMsgProcess: function(message, text){
					message.MMActualContent = text;
					message._noSupportMsg = true;
					this._textMsgProcess(message);
				},
				/**
				 * 消息撤回处理
				 * @param message 消息体
				 * @private
				 */
				_recalledMsgProcess: function (message) {
					var me = this,
						str = utilFactory.htmlDecode(message.MMActualContent),
						recallMsg = '',
						msgIndex,
						actualSender,
						content = _("ded861c"),
						userMessages = me.getChatMessage(message.MMPeerUserName);
		
					str = utilFactory.encodeEmoji(str);
					recallMsg = utilFactory.xml2json(str.replace(/<br\/>/g,'')).revokemsg;
					if(recallMsg.msgid == 0){
						for (var j = userMessages.length - 1; j >= 0; --j) {//find the last msg sending by myself
							if(userMessages[j].FromUserName == accountFactory.getUserName()) {
								msgIndex = j;
								break;
							}
						}
					}else {
						msgIndex = me._findMessageByMsgId(userMessages, recallMsg.msgid);
					}
					if(msgIndex > -1){
						//modify recall message info
						var oldMsg = userMessages[msgIndex];
						if(!oldMsg.MMIsSend){
							var contact = contactFactory.getContact(message.MMActualSender,message.MMPeerUserName);
							actualSender = contact ? contact.getDisplayName(message.MMPeerUserName) : '';
						}else{
							actualSender = _("df1fd91");
						}
						angular.extend(oldMsg,{
							MMRecall:true,
							MsgType: confFactory.MSGTYPE_SYS,
							MMActualContent: actualSender + content,
							MMDigest:actualSender + content,
							_h:0
						});
						//update chatList
						me.getChatList();
					}else{
						//add new system message
						//应该不用显示了
						/*me.messageProcess({
							MsgType: confFactory.MSGTYPE_SYS,
							Content: _("7d048b1")
						});*/
					}
				},
				/**
				 * 推荐消息处理
				 * @param message 消息体
				 * @private
				 */
				_recommendMsgProcess : function(message) {
					message.Contact = message.RecommendInfo;
					if (message.MsgType == confFactory.MSGTYPE_VERIFYMSG) {
						message.Content = message.Contact.NickName||message.Contact.UserName + _("ebeaf99");
					} else {
						message.Content = message.Contact.NickName||message.Contact.UserName + "text_posible_friend_msg_digest";
					}
				},
				/**
				 * 认证消息处理
				 * @param message 消息体
				 * @private
				 */
				_verifyMsgProcess : function(message) {
					message.MMDigest = message.RecommendInfo.NickName + _("ebeaf99");
					for(var attr in message.RecommendInfo){
						if(!message.RecommendInfo[attr]){
							delete message.RecommendInfo[attr];
						}
					}
					message.RecommendInfo.HeadImgUrl = utilFactory.getContactHeadImgUrl({
						UserName:message.RecommendInfo.UserName,
						Skey:accountFactory.getSkey(),
						MsgId:message.MsgId
					});
					message.RecommendInfo.MMFromVerifyMsg = true;
					// 如果推荐联系人不在我的联系人列表&陌生人列表，添加到陌生人列表
					//if(!contactFactory.getContact(message.RecommendInfo.UserName)){
						contactFactory.addStrangerContact(message.RecommendInfo);
					//}
				},
				/**
				 * 名片消息处理
				 * @param message 消息体
				 * @private
				 */
				_shareCardProcess : function (message) {
					if (message.MMActualSender == accountFactory.getUserName()) {
						message.MMDigest += _("9a2223f") + message.RecommendInfo.NickName;
					} else {
						message.MMDigest += _("dd14577") + message.RecommendInfo.NickName;
					}
					for(var attr in message.RecommendInfo){
						if(!message.RecommendInfo[attr]){
							delete message.RecommendInfo[attr];
						}
					}
					var content = utilFactory.htmlDecode(message.MMActualContent).replace(/<br\/>/g,'');
					content = utilFactory.encodeEmoji(content);
					content = utilFactory.xml2json(content);
					message.MMUserName = content.alias || content.username;
					//message.MMUserName = message.RecommendInfo.Alias || message.RecommendInfo.Username;
					message.RecommendInfo.NickName = utilFactory.decodeEmoji(message.RecommendInfo.NickName);
					message.RecommendInfo.HeadImgUrl = utilFactory.getContactHeadImgUrl({
						UserName:message.RecommendInfo.UserName,
						Skey:accountFactory.getSkey(),
						MsgId:message.MsgId
					});
		
					// 如果推荐名片联系人不在我的联系人列表&陌生人列表，添加到陌生人列表
					if(!contactFactory.getContact(message.RecommendInfo.UserName,'',true)){
						contactFactory.addStrangerContact(message.RecommendInfo);
					}
				},
				/**
				 * 系统消息处理
				 * @param msg 消息体
				 * @private
				 */
				_systemMsgProcess: function (message) {
					var _aLinkArray = message.MMActualContent.match(/&lt;a href=(?:'|").*?(?:'|").*?&gt;.*?&lt;\/a&gt;/g);//<a href=".*?".*?>.*?</a>
					if (_aLinkArray){
						var _aLink, _sLink;
						for (var i = 0, len = _aLinkArray.length; i < len; ++i) {
							_aLink = /&lt;a href=(?:'|")(.*?)(?:'|").*?&gt;.*?&lt;\/a&gt;/.exec(_aLinkArray[i]);
							if (!_aLink || !_aLink[1]) continue;
							_sLink = _aLink[1];
						   /* if (/^(weixin:\/\/findfriend\/verifycontact)$/.test(_sLink) || $.isUrl(_sLink) && /\.qq\.com/.test(_sLink)) {
								message.MMActualContent = message.MMActualContent.replace(_aLink[0], utilFactory.htmlDecode(_aLink[0]));
							}
							message.MMActualContent = message.MMActualContent.replace(/<a href=(?:'|")weixin:\/\/findfriend\/verifycontact(?:'|")>/, '<a ng-click="showProfile($event,message.MMActualSender)" href="javascript:;">');//替换为内置的弹窗
							*/
							message.MMActualContent = message.MMActualContent.replace(/&lt;a href=(?:'|")weixin:\/\/.*?&lt;\/a&gt;/, '');//去掉微信协议的链接
						}
					}
					//message.MMActualContent = utilFactory.removeHtmlStrTag(message.MMActualContent);
					message.MMDigest += message.MMActualContent;
				},
				/**
				 * 桌面通知
				 * @param message
				 * @private
				 */
				_notify: function(message){
					if(window.isFocus) return;
		
					function notify(){
						var contact = contactFactory.getContact(message.MMPeerUserName),
							displayName = contact ? contact.getDisplayName(message.MMPeerUserName) : '',
							icon = contact? contact.HeadImgUrl : '';
		
						// 过滤表情html为[表情]
						// <img src="/zh_CN/htmledition/v2/images/spacer.gif" class="emoji emoji1f609">
						// <img src="/zh_CN/htmledition/v2/images/icon/qqface/48.png">
						// <span class="emoji emoji1f639"></span>
						var content = message.MMDigest.replace(/(<img.*?\/>)|<span class="emoji.*?<\/span>/g, _("809bb9d"));
						var notifyBody = utilFactory.clearHtmlStr(content);
						var resultNotifyBody = '';
						var maxLength=80,curLength = 0;
						for(var i = 0;i<notifyBody.length;i++){
							if(notifyBody.charCodeAt(i)<=128){
								curLength += 1;
							}else{
								curLength += 2;
							}
							if(curLength >= maxLength){
								resultNotifyBody = notifyBody.slice(0,i+1);
								if(i<notifyBody.length -1){
									resultNotifyBody += '…';
								}
								break;
							}else{
								resultNotifyBody = notifyBody;
							}
						}
		
		
		
		
						var notification = notificationFactory.createNotification(utilFactory.clearHtmlStr(displayName), {
							body: resultNotifyBody,
							icon: icon
						});
						if(notification){
							notification.onclick = function(){
								try{
									window.focus();
									$rootScope.$broadcast('root:notification:click', message.FromUserName);
								}catch (e) {
									reportService.report(reportService.ReportType.logicError,{
										text:'notification click'
									})
								}
							};
						}
		
		
					}
		
					if(notificationFactory.permissionLevel() === notificationFactory.PERMISSION_DEFAULT){
						notificationFactory.requestPermission(notify);
					}else{
						notify();
					}
				},
		
				localDelete:function(message){
					var me = this,
						msgIndex,
						userMessages = me.getChatMessage(message.MMPeerUserName);
					msgIndex = me._findMessageByMsgId(userMessages, message.MsgId);
					userMessages.splice(msgIndex,1);
					me.getChatList();
				},
		
		
		
				revokemsg:function(message){
					var self = this;
					$http({
						method: "POST",
						url: confFactory.API_webwxrevokemsg,
						data: angular.extend(accountFactory.getBaseRequest(), {
							SvrMsgId :  message.MsgId,
							ToUserName : message.ToUserName,
							ClientMsgId:message.ClientMsgId // 必须给一个ClientMsgId字段...
						})
					}).success(function (data) {
		
						if(data.BaseResponse.Ret == 0){
							angular.extend(message,{
								MMRecall:true,
								MsgType: confFactory.MSGTYPE_SYS,
								MMActualContent: _("df1fd91") +  _("ded861c"),
								MMDigest:_("df1fd91") +  _("ded861c"),
								_h:0
							});
							//update chatList
							self.getChatList();
						}else{
							alert(data.BaseResponse.ErrMsg || '撤回失败')
						}
						// do nothing
					}).error(function (data) {
						// do nothing
						alert('撤回失败')
					});
				},
		
		
				/**
				 * 通知客户端修改消息状态
				 * @param  {[type]} userName
				 * @param  {[type]} code
				 */
				notifyMobile : function(userName, code) {
					$http({
						method: "POST",
						url: confFactory.API_webwxstatusnotify,
						data: angular.extend(accountFactory.getBaseRequest(), {
							Code : code,
							FromUserName : accountFactory.getUserName(),
							ToUserName : userName,
							ClientMsgId:utilFactory.now() // 必须给一个ClientMsgId字段...
						})
					}).success(function (data) {
						// do nothing
					}).error(function (data) {
						// do nothing
					});
				},
				_getMessagePeerUserName: function(message){
		
					var isSend = message.FromUserName == accountFactory.getUserName() || message.FromUserName == "";
		
					return isSend ? message.ToUserName : message.FromUserName;
				},
				_findMessageByMsgId: function (messages,msgId) {
					for(var i = 0; i < messages.length; ++i){
						if(messages[i].MsgId == msgId){
							return i;
						}
					}
					return -1;
				},
				 _calcMsgDisplayTime: function (lastMessage, currentMessage) {
					if (!currentMessage || currentMessage.MsgType < 0) {
						return;
		
					} else if (!lastMessage || lastMessage.MsgType < 0) {
						var createTime = new Date(currentMessage.CreateTime * 1000);
						currentMessage.MMDigestTime = createTime.getHours() + ":" + utilFactory.formatNum(createTime.getMinutes(), 2);
						currentMessage.MMDisplayTime = currentMessage.CreateTime;
						currentMessage.MMTime = currentMessage.MMDigestTime;
					} else {
						var createTime = new Date(currentMessage.CreateTime * 1000);
						currentMessage.MMDigestTime = createTime.getHours() + ":" + utilFactory.formatNum(createTime.getMinutes(), 2);
		
						if (Math.abs(lastMessage.MMDisplayTime - currentMessage.CreateTime) >= 180 ) {
							currentMessage.MMDisplayTime = currentMessage.CreateTime;
							currentMessage.MMTime = currentMessage.MMDigestTime;
						} else {
							currentMessage.MMDisplayTime = lastMessage.MMDisplayTime;
							currentMessage.MMTime = "";
						}
					}
				},
				_findByVerifyMsgUserName: function(messages, userName){
					for(var i = 0; i < messages.length; ++i){
						var message = messages[i];
						if(message.MsgType == confFactory.MSGTYPE_VERIFYMSG
							&& message.RecommendInfo.UserName == userName){
							return i;
						}
					}
					return -1;
				}
			};
				function handleChatList(chatList){
					var topList = [];
					var item;
					var normalList = [];
					for(var i = 0;i<chatList.length;i++){
						item = chatList[i];
						if(item.isTop()){
							topList.push(item);
						}else{
							normalList.push(item);
						}
					}
					[].unshift.apply(normalList,topList);
					return normalList;
				}
		
			return service;
		}]);
		})();
	
	
	/***/ }),
	/* 291 */
	/***/ (function(module, exports) {
	
		(function(_aoUndefined){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('chatroomFactory', [
			'$rootScope',
			'$timeout', 
			'$http',
			'$q',
			'contactFactory',
			'accountFactory', 
			'emojiFactory',
			'confFactory', 
			'utilFactory',
				'reportService',
				'mmHttp',
			function($rootScope,$timeout,$http, $q, contactFactory,accountFactory,emojiFactory, confFactory, utilFactory,reportService,mmHttp) {
		
			var _filterContacts = {},
				_currentContact;
		
			var service = {
				setCurrentContact: function (contact) {
					_currentContact = contact;
				},
				getCurrentContact: function () {
					return _currentContact;
				},
				setFilterContacts: function (contacts) {
					_filterContacts = contacts || {};
				},
				getFilterContacts: function () {
					return _filterContacts;
				},
				/**
				 * 创建群聊
				 * @param  {[type]} memberList
				 */
				create: function (memberList) {
					var deferred = $q.defer();
					var postData = angular.extend({
							MemberCount : memberList.length,
							MemberList : memberList,
							Topic:''
						}, accountFactory.getBaseRequest());
		
					$http({
						method:'POST',
						url:confFactory.API_webwxcreatechatroom + '?r=' + utilFactory.now(),
						data:postData/*,
						MMRetry:{
							serial:true
						}*/
					}).success(function(data){
						if(data && data.BaseResponse && data.BaseResponse.Ret == 0){
							deferred.resolve(data);
						}else{
							reportService.report(reportService.ReportType.netError,{
								text:'create classroom net error',
								url:confFactory.API_webwxcreatechatroom,
								params:postData,
								res:data
							})
							deferred.reject(data);
						}
					}).error(function(data){
						deferred.reject(data);
		
		
						reportService.report(reportService.ReportType.netError,{
							text:'create classroom net error',
							url:confFactory.API_webwxcreatechatroom,
							params:postData
						})
					});
					return deferred.promise;
				},
				/**
				 * 添加群成员
				 * @param {[type]}   userName   [description]
				 * @param {[type]}   addMembers [description]
				 * @param {Function} callback   [description]
				 */
				addMember : function(userName, addMembers, callback) {
					var contact = contactFactory.getContact(userName);
					if(contact.MemberList.length + addMembers.split(',').length >= 40){
						console.log('invite',contact.MemberList.length + addMembers.split(',').length);
						this._update("invitemember", userName, {
							inviteMembers:addMembers
						}, callback);
					}else{
						this._update("addmember", userName, {
							addMembers:addMembers
						}, callback);
					}
		
		
		
				},
				delMember : function(userName, delMember) {
					this._update("delmember", userName, {
						delMember:delMember
					});
					var contact = contactFactory.getContact(userName);
				},
				quit: function (userName) {
					this._update("quitchatroom", userName);
				},
				modTopic : function(userName, topic) {
					this._update("modtopic", userName, {
						topic:topic
					});
				},
				_update : function(fun,userName,data,/*  addMembers, delMember, topic,*/ callback) {
					//var deferred = $q.defer();
					data =data || {};
					var postData = angular.extend({
						AddMemberList : data.addMembers,
						DelMemberList : data.delMember,
						InviteMemberList:data.inviteMembers,
						NewTopic : data.topic,
						ChatRoomName : userName
					}, accountFactory.getBaseRequest());
					var url = confFactory.API_webwxupdatechatroom + '?fun=' + fun;
					$http({
						method:'POST',
						url:url,
						data:postData/*,
						MMRetry:{
							serial:true
						}*/
					}).success(function(res){
						//deferred.resolve(data);
						var contact = contactFactory.getContact(userName);
						if (fun == "delmember") {
							for (var i=contact.MemberList.length-1; i>=0; i--) {
								if (contact.MemberList[i].UserName == data.delMember) {
									contact.MemberList.splice(i, 1);
								}
							}
							contact.MemberCount = contact.MemberList.length;
							//contactFactory.addContact(contact);
						} else if (fun == "modtopic") {
							/*$('.chatListColumn[username="'+userName+'"]').find('.nickName').find('.name').text(topic);
							contact.DisplayName = topic;
							$("#messagePanelTitle").html(_aoWebMM.util.getChatTitle(contact));
							contactFactory.addContact(contact);*/
						}
						callback && callback(res);
						
					}).error(function(data){
						//deferred.reject('error:'+data);
						reportService.report(reportService.ReportType.netError,{
							text:'update classroom net error',
							url:url,
							params:postData
						})
					});
					//return deferred.promise;
				}
			};
		
			return service;
		}]);
		})();
	
	/***/ }),
	/* 292 */
	/***/ (function(module, exports) {
	
		(function() {
		'use strict';
		
		/* Services */
		angular.module('Services').factory('accountFactory', [ '$q', 'confFactory', 'utilFactory',
		function( $q, confFactory, utilFactory) {
		
			var _userInfo = {},
				_chatList = [],
				_synckey = null,
				_synccheckkey = null,
				_sid,
				_skey,
				_passticket,
				_clientVerInfo = {
					type: "",
					ver: ""
				};
			var _notityState = utilFactory.getCookie('MM_WX_NOTIFY_STATE') === "" ?
					confFactory.MM_NOTIFY_OPEN : utilFactory.getCookie('MM_WX_NOTIFY_STATE'), // 默认为打开桌面通知
				_soundState = utilFactory.getCookie('MM_WX_SOUND_STATE') === "" ?
					confFactory.MM_SOUND_OPEN : utilFactory.getCookie('MM_WX_SOUND_STATE'); // 默认为打开音效
			
			var _loginTime = 0;
			var _rmsgcount = 0; // 收消息数
			var _rconvcount = 0; // 收消息会话数
			var _smsgcount = 0; // 发消息数
			var _sconvcount = 0; // 发消息会话数
		
			var service = {
				openNotify: function () {
					_notityState = confFactory.MM_NOTIFY_OPEN;
					utilFactory.setCookie('MM_WX_NOTIFY_STATE', confFactory.MM_NOTIFY_OPEN);
				},
				closeNotify: function () {
					_notityState = confFactory.MM_NOTIFY_CLOSE;
					utilFactory.setCookie('MM_WX_NOTIFY_STATE', confFactory.MM_NOTIFY_CLOSE);
				},
				isNotifyOpen:function () {
					return !!_notityState;
				},
				openSound: function () {
					_soundState = confFactory.MM_SOUND_OPEN;
					utilFactory.setCookie('MM_WX_SOUND_STATE', confFactory.MM_SOUND_OPEN);
				},
				closeSound: function () {
					_soundState = confFactory.MM_SOUND_CLOSE;
					utilFactory.setCookie('MM_WX_SOUND_STATE', confFactory.MM_SOUND_CLOSE);
				},
				isSoundOpen:function () {
					return !!_soundState;
				},
				setUserInfo: function(user) {
					angular.extend(_userInfo, user);
				},
				updateUserInfo: function(profile,changeCallback) {
					var me = this;
					if (!profile) return;
		
					if (profile.BitFlag == confFactory.PROFILE_BITFLAG_CHANGE) {
						var user = {};
						if (profile.HeadImgUpdateFlag) user.HeadImgUrl = profile.HeadImgUrl;
						if (profile.NickName.Buff) user.NickName = profile.NickName.Buff;
						me.setUserInfo(user);
						changeCallback && changeCallback();
					}
				},
				getUserInfo: function() {
					return _userInfo;
				},
				getUserName: function() {
					return this.getUserInfo() && this.getUserInfo().UserName;
				},
				getSyncKey: function() {
					return _synckey || {
						List: []
					};
				},
				getFormateSyncCheckKey: function() {
		
					var synncheckkey = _synccheckkey || this.getSyncKey();
					var synccheckkeyList =synncheckkey.List,
						synccheckkeyFormat = [];
		
					for (var i = 0,len = synccheckkeyList.length; i < len; i++) {
						synccheckkeyFormat.push(synccheckkeyList[i].Key + "_" + synccheckkeyList[i].Val);
					}
					return synccheckkeyFormat.join('|');
				},
				setSyncCheckKey:function(synccheckkey){
					if (synccheckkey && synccheckkey.Count > 0) {
						_synccheckkey = synccheckkey;
					} else {
						utilFactory.log("JS Function: setSyncCheckKey. Error. no synccheckkey");
					}
				},
				setLoginTime: function(loginTime) {
					_loginTime = loginTime;
				},
				getLoginTime: function() {
					return _loginTime;
				},
				setRMsgCount: function(rmsgcount) {
					_rmsgcount = rmsgcount;
				},
				getRMsgCount: function() {
					return _rmsgcount;
				},
				setRConvCount: function(rconvcount) {
					_rconvcount = rconvcount;
				},
				getRConvCount: function() {
					return _rconvcount;
				},
				setSMsgCount: function(smsgcount) {
					_smsgcount = smsgcount;
				},
				getSMsgCount: function() {
					return _smsgcount;
				},
				setSConvCount: function(sconvcount) {
					_sconvcount = sconvcount;
				},
				getSConvCount: function() {
					return _sconvcount;
				},
				setSyncKey: function(synckey) {
					//console.log('setSyncKey', synckey);
					if (synckey && synckey.Count > 0) {
						_synckey = synckey;
					} else {
		/*                reportService.report(reportService.ReportType.uploaderError,{
							text:'chooseFile 上传失败',
							reason:reason,
							fileName: this.ext,
							fileSize: this.size
						})*/
		
						utilFactory.log("JS Function: setSyncKey. Error. no synckey");
					}
				},
				setPassticket: function(passticket) {
					_passticket = passticket;
				},
				getPassticket: function() {
					return _passticket;
				},
				getSid: function() {
					return _sid || (_sid = utilFactory.getCookie("wxsid"));
				},
				setSid: function(sid) {
					if (sid) {
						_sid = sid;
					}
				},
				getSkey: function() {
					return _skey || '';
				},
				setSkey: function(skey) {
					if (skey) {
						_skey = skey;
					}
				},
				setUin: function(uin) {
					this.getUserInfo().Uin = uin
				},
				getUin: function() {
					return this.getUserInfo() && this.getUserInfo().Uin || utilFactory.getCookie("wxuin");
				},
				getBaseRequest: function() {
					return {
						"BaseRequest": {
							Uin: this.getUin(),
							Sid: this.getSid(),
							Skey: this.getSkey(),
							DeviceID: this.getDeviceID()
						}
					};
				},
				getDeviceID: function() {
					return 'e' + ("" + Math.random().toFixed(15)).substring(2, 17);
				},
				isHigherVer: function() {
					return _clientVerInfo.ver >= 4.5;
				},
				setClientVer: function(_asVer) {
					var _sVer = parseInt(_asVer, 10).toString(16),
					_sType = _sVer.substr(0, 1),
					_sVer = _sVer.substr(1, 3).replace("0", ".");
					_clientVerInfo.type = _sType;
					_clientVerInfo.ver = _sVer;
				}
			};
		
			// 设置的init
			if(_notityState == confFactory.MM_NOTIFY_OPEN) service.openNotify();
			else service.closeNotify();
		
			if(_soundState == confFactory.MM_SOUND_OPEN) service.openSound();
			else service.closeSound();
		
			return service;
		}]);
		
		})();
	
	/***/ }),
	/* 293 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('confFactory', ['$q', function( $q) {
		
			var host = location.host,
				loginHost = "login.weixin.qq.com",
				fileHost = "file.wx.qq.com",
				pushHost = "webpush.weixin.qq.com";
		
			if(host.indexOf("wx2.qq.com") > -1){
				loginHost = "login.wx2.qq.com";
				fileHost = "file.wx2.qq.com";
				pushHost = "webpush.wx2.qq.com";
			}else if(host.indexOf("wx8.qq.com") > -1){
				loginHost = "login.wx8.qq.com";
				fileHost = "file.wx8.qq.com";
				pushHost = "webpush.wx8.qq.com";
			}
			else if(host.indexOf("qq.com") > -1){
				loginHost = "login.wx.qq.com";
				fileHost = "file.wx.qq.com";
				pushHost = "webpush.wx.qq.com";
		
			}else if(host.indexOf("web2.wechat.com") > -1){
				loginHost = "login.web2.wechat.com";
				fileHost = "file.web2.wechat.com";
				pushHost = "webpush.web2.wechat.com";
			}else if(host.indexOf("wechat.com") > -1){
				loginHost = "login.web.wechat.com";
				fileHost = "file.web.wechat.com";
				pushHost = "webpush.web.wechat.com";
			}
		
			var lang = (navigator.language || navigator.browserLanguage);
				if (!lang) lang = "zh-cn";
				lang = lang.split("-");
				lang = lang[0].toLowerCase() + "_" + (lang[1] || "").toUpperCase();
		
		
				var isClientVersion = false;
		
			if(location.href.indexOf('target=t')>=0 || window.__target === 't'){
				isClientVersion = true
			}
			var service = {
				LANG : lang,
		
				EMOTICON_REG: 'img\\sclass="(qq)?emoji (qq)?emoji([\\da-f]*?)"\\s(text="[^<>(\\s]*")?\\s?src="[^<>(\\s]*"\\s*', // img class="emoji emoji11" text="[..]" src=".."
		
		
				RES_PATH: "/zh_CN/htmledition/v2/",
				// 需要用到RES_PATH的静态变量请参考 写在接近页面底部的 RES_IMG_DEFAULT
				API_jsLogin: "https://" + loginHost + "/jslogin?appid=wx782c26e4c19acffb&redirect_uri="
							+ encodeURIComponent(location.protocol + "//" + location.host + "/cgi-bin/mmwebwx-bin/webwxnewloginpage"
						+(isClientVersion?'?mod=desktop':'')) + "&fun=new&lang=" + lang,
				API_login: 'https://' + loginHost + '/cgi-bin/mmwebwx-bin/login',
				API_synccheck: 'https://' + pushHost + '/cgi-bin/mmwebwx-bin/synccheck',
				API_webwxdownloadmedia: 'https://' + fileHost + '/cgi-bin/mmwebwx-bin/webwxgetmedia',
				API_webwxuploadmedia: 'https://' + fileHost + '/cgi-bin/mmwebwx-bin/webwxuploadmedia',
				API_webwxpreview: '/cgi-bin/mmwebwx-bin/webwxpreview',
				API_webwxinit: "/cgi-bin/mmwebwx-bin/webwxinit?r="+~new Date(),
				API_webwxgetcontact: "/cgi-bin/mmwebwx-bin/webwxgetcontact",
				API_webwxsync: "/cgi-bin/mmwebwx-bin/webwxsync",
				API_webwxbatchgetcontact: '/cgi-bin/mmwebwx-bin/webwxbatchgetcontact',
				API_webwxgeticon: '/cgi-bin/mmwebwx-bin/webwxgeticon',
				API_webwxsendmsg: '/cgi-bin/mmwebwx-bin/webwxsendmsg',
				API_webwxsendmsgimg: '/cgi-bin/mmwebwx-bin/webwxsendmsgimg',
				API_webwxsendmsgvedio: '/cgi-bin/mmwebwx-bin/webwxsendvideomsg',
				API_webwxsendemoticon: '/cgi-bin/mmwebwx-bin/webwxsendemoticon',
				API_webwxsendappmsg: '/cgi-bin/mmwebwx-bin/webwxsendappmsg',
				API_webwxgetheadimg: '/cgi-bin/mmwebwx-bin/webwxgetheadimg',
				API_webwxgetmsgimg: '/cgi-bin/mmwebwx-bin/webwxgetmsgimg',
				API_webwxgetmedia: '/cgi-bin/mmwebwx-bin/webwxgetmedia',
				API_webwxgetvideo: '/cgi-bin/mmwebwx-bin/webwxgetvideo',
				API_webwxlogout: '/cgi-bin/mmwebwx-bin/webwxlogout',
				API_webwxgetvoice: '/cgi-bin/mmwebwx-bin/webwxgetvoice',
				API_webwxupdatechatroom: '/cgi-bin/mmwebwx-bin/webwxupdatechatroom',
				API_webwxcreatechatroom:'/cgi-bin/mmwebwx-bin/webwxcreatechatroom',
				API_webwxstatusnotify: '/cgi-bin/mmwebwx-bin/webwxstatusnotify',
				API_webwxcheckurl: '/cgi-bin/mmwebwx-bin/webwxcheckurl',
				API_webwxverifyuser: '/cgi-bin/mmwebwx-bin/webwxverifyuser',
				API_webwxfeedback: '/cgi-bin/mmwebwx-bin/webwxsendfeedback',
				API_webwxreport: '/cgi-bin/mmwebwx-bin/webwxstatreport',
				API_webwxsearch: '/cgi-bin/mmwebwx-bin/webwxsearchcontact',
				API_webwxoplog: '/cgi-bin/mmwebwx-bin/webwxoplog',
				API_checkupload:'/cgi-bin/mmwebwx-bin/webwxcheckupload',
				/*
				* 消息撤回
				* */
				API_webwxrevokemsg:'/cgi-bin/mmwebwx-bin/webwxrevokemsg',
				API_webwxpushloginurl: '/cgi-bin/mmwebwx-bin/webwxpushloginurl',
				oplogCmdId:{
					TOPCONTACT: 3,
					MODREMARKNAME:2
				},
				//
				SP_CONTACT_FILE_HELPER : "filehelper",
				SP_CONTACT_NEWSAPP : "newsapp",
				SP_CONTACT_RECOMMEND_HELPER:"fmessage",
		
				// contact flag
				CONTACTFLAG_CONTACT : 0x01,
				CONTACTFLAG_CHATCONTACT : 0x02,
				CONTACTFLAG_CHATROOMCONTACT : 0x04,
				CONTACTFLAG_BLACKLISTCONTACT : 0x08,
				CONTACTFLAG_DOMAINCONTACT : 0x10,
				CONTACTFLAG_HIDECONTACT : 0x20,
				CONTACTFLAG_FAVOURCONTACT : 0x40,
				CONTACTFLAG_3RDAPPCONTACT : 0x80,
				CONTACTFLAG_SNSBLACKLISTCONTACT : 0x100,
				CONTACTFLAG_NOTIFYCLOSECONTACT : 0x200,
				CONTACTFLAG_TOPCONTACT : 0x800,
				// verify flag
				MM_USERATTRVERIFYFALG_BIZ : 0x1, // 小商家
				MM_USERATTRVERIFYFALG_FAMOUS : 0x2,
				MM_USERATTRVERIFYFALG_BIZ_BIG : 0x4, // 大商家
				MM_USERATTRVERIFYFALG_BIZ_BRAND : 0x8, // 品牌商家
				MM_USERATTRVERIFYFALG_BIZ_VERIFIED : 0x10, // 认证
		
				MM_DATA_TEXT : 1,
				MM_DATA_HTML : 2,
				MM_DATA_IMG : 3,
				MM_DATA_PRIVATEMSG_TEXT : 11,
				MM_DATA_PRIVATEMSG_HTML : 12,
				MM_DATA_PRIVATEMSG_IMG : 13,
				MM_DATA_VOICEMSG : 34,
				MM_DATA_PUSHMAIL : 35,
				MM_DATA_QMSG : 36,
				MM_DATA_VERIFYMSG : 37,
				MM_DATA_PUSHSYSTEMMSG : 38,
				MM_DATA_QQLIXIANMSG_IMG : 39,
				MM_DATA_POSSIBLEFRIEND_MSG : 40,
				MM_DATA_SHARECARD : 42,
				MM_DATA_VIDEO : 43,
				MM_DATA_VIDEO_IPHONE_EXPORT : 44,
				MM_DATA_EMOJI : 47,
				MM_DATA_LOCATION : 48,
				MM_DATA_APPMSG : 49, // AppMsg
				MM_DATA_VOIPMSG : 50, // voip msg
				MM_DATA_STATUSNOTIFY : 51, //
				MM_DATA_VOIPNOTIFY : 52, // voip 结束消息
				MM_DATA_VOIPINVITE : 53, // voip 邀请
				MM_DATA_MICROVIDEO : 62, // 微视频
				MM_DATA_SYSNOTICE : 9999,
				MM_DATA_SYS : 10000,
				MM_DATA_RECALLED : 10002,
		
				//msg type
				MSGTYPE_TEXT:1,
				MSGTYPE_IMAGE:3,
				MSGTYPE_VOICE:34,
				MSGTYPE_VIDEO:43,
				MSGTYPE_MICROVIDEO:62,
				MSGTYPE_EMOTICON:47,
				MSGTYPE_APP:49,
				MSGTYPE_VOIPMSG : 50, // voip msg
				MSGTYPE_VOIPNOTIFY : 52, // voip 结束消息
				MSGTYPE_VOIPINVITE : 53, // voip 邀请
				MSGTYPE_LOCATION : 48,
				MSGTYPE_STATUSNOTIFY:51,
				MSGTYPE_SYSNOTICE:9999,
				MSGTYPE_POSSIBLEFRIEND_MSG:40,
				MSGTYPE_VERIFYMSG:37,
				MSGTYPE_SHARECARD:42,
				MSGTYPE_SYS : 10000,
				MSGTYPE_RECALLED : 10002,
		
				//msg send status
				MSG_SEND_STATUS_READY:0,
				MSG_SEND_STATUS_SENDING:1,
				MSG_SEND_STATUS_SUCC:2,
				MSG_SEND_STATUS_FAIL:5,
		
				//app msgtype
				APPMSGTYPE_TEXT : 1,
				APPMSGTYPE_IMG : 2,
				APPMSGTYPE_AUDIO : 3,
				APPMSGTYPE_VIDEO : 4,
				APPMSGTYPE_URL : 5,
				APPMSGTYPE_ATTACH : 6,
				APPMSGTYPE_OPEN : 7,
				APPMSGTYPE_EMOJI : 8,
				APPMSGTYPE_VOICE_REMIND : 9,
				APPMSGTYPE_SCAN_GOOD : 10,
				APPMSGTYPE_GOOD : 13,
				APPMSGTYPE_EMOTION : 15,
				APPMSGTYPE_CARD_TICKET : 16,
				APPMSGTYPE_REALTIME_SHARE_LOCATION : 17,
				APPMSGTYPE_TRANSFERS: 2000,
				APPMSGTYPE_RED_ENVELOPES: 2001,
				APPMSGTYPE_READER_TYPE:100001,//自定义的type
		
				//upload media type
				UPLOAD_MEDIA_TYPE_IMAGE : 1,
				UPLOAD_MEDIA_TYPE_VIDEO : 2,
				UPLOAD_MEDIA_TYPE_AUDIO : 3,
				UPLOAD_MEDIA_TYPE_ATTACHMENT : 4,
		
				//Profile bitFlag
				PROFILE_BITFLAG_NOCHANGE: 0,
				PROFILE_BITFLAG_CHANGE: 190,
		
				// chatroom mute
				CHATROOM_NOTIFY_OPEN : 0x1,
				CHATROOM_NOTIFY_CLOSE : 0x0,
		
				// status notify
				StatusNotifyCode_READED : 1,
				StatusNotifyCode_ENTER_SESSION : 2,
				StatusNotifyCode_INITED : 3,
				StatusNotifyCode_SYNC_CONV : 4,
				StatusNotifyCode_QUIT_SESSION : 5,
		
				// VerifyUserOpcode
				VERIFYUSER_OPCODE_ADDCONTACT : 1,
				VERIFYUSER_OPCODE_SENDREQUEST : 2,
				VERIFYUSER_OPCODE_VERIFYOK : 3,
				VERIFYUSER_OPCODE_VERIFYREJECT : 4,
				VERIFYUSER_OPCODE_SENDERREPLY : 5,
				VERIFYUSER_OPCODE_RECVERREPLY : 6,
		
				// add contact scene
				ADDSCENE_PF_QQ : 4, // 通过可能认识的QQ好友
				ADDSCENE_PF_EMAIL : 5, // 通过可能认识的QQMail好友
				ADDSCENE_PF_CONTACT : 6, // 通过把我加到通讯录的人
				ADDSCENE_PF_WEIXIN : 7, // 通过可能认识的微信好友(二度关系)
				ADDSCENE_PF_GROUP : 8, // 通过可能认识的群好友
				ADDSCENE_PF_UNKNOWN : 9, // “可能认识的好友”（无法区分来源）
				ADDSCENE_PF_MOBILE : 10, // 手机通讯录
				ADDSCENE_PF_WEB : 33, // web
		
				TIMEOUT_SYNC_CHECK:0,
		
				EMOJI_FLAG_GIF: 2,
		
				KEYCODE_BACKSPACE: 8,
				KEYCODE_ENTER: 13,
				KEYCODE_SHIFT: 16,
				KEYCODE_ESC: 27,
				KEYCODE_DELETE: 34,
				KEYCODE_ARROW_LEFT: 37,
				KEYCODE_ARROW_UP: 38,
				KEYCODE_ARROW_RIGHT: 39,
				KEYCODE_ARROW_DOWN: 40,
				KEYCODE_NUM2: 50,
				KEYCODE_AT: 64,
				KEYCODE_NUM_ADD: 107,
				KEYCODE_NUM_MINUS: 109,
				KEYCODE_ADD: 187,
				KEYCODE_MINUS: 189,
		
				// 桌面通知的关闭与打开
				MM_NOTIFY_CLOSE:0,
				MM_NOTIFY_OPEN:1,
		
				// 音效的关闭与打开
				MM_SOUND_CLOSE:0,
				MM_SOUND_OPEN:1,
		
				MM_SEND_FILE_STATUS_QUEUED:0,
				MM_SEND_FILE_STATUS_SENDING:1,
				MM_SEND_FILE_STATUS_SUCCESS:2,
				MM_SEND_FILE_STATUS_FAIL:3,
				MM_SEND_FILE_STATUS_CANCEL:4,
		
				//区分经web端处理过的表情的后缀
				MM_EMOTICON_WEB: "_web"
			};
			angular.extend(service, {
				RES_IMG_DEFAULT: service.RES_PATH + 'images/img.gif',
				RES_IMG_PLACEHOLDER: service.RES_PATH + 'images/spacer.gif',
				RES_SOUND_RECEIVE_MSG: service.RES_PATH + 'sound/msg.mp3',
				RES_SOUND_SEND_MSG: service.RES_PATH + 'sound/text.mp3'
			});
		
			if(/mmdebug=local/.test(document.location.search)){
				angular.extend(service, {
					TIMEOUT_SYNC_CHECK:3000,
					API_jsLogin: "/zh_CN/htmledition/v2/api/jsLogin.js",
					API_login:'/zh_CN/htmledition/v2/api/login.js',
					API_webwxinit:"/zh_CN/htmledition/v2/api/webwxinit.json",
					API_webwxgetcontact:"/zh_CN/htmledition/v2/api/webwxgetcontact.json",
					API_webwxsync:"/zh_CN/htmledition/v2/api/webwxsync.json",
					API_synccheck:'/zh_CN/htmledition/v2/api/synccheck.js',
					API_webwxbatchgetcontact:'/zh_CN/htmledition/v2/api/webwxbatchgetcontact.json',
					API_webwxgeticon:'/zh_CN/htmledition/v2/images/webwxgeticon.jpg',
					API_webwxgetheadimg:'/zh_CN/htmledition/v2/images/webwxgeticon.jpg',
					API_webwxgetmsgimg:'/zh_CN/htmledition/v2/images/webwxgeticon.jpg',
					API_webwxgetmedia:'/zh_CN/htmledition/v2/images/webwxgeticon.jpg',
					API_webwxgetvideo:'/zh_CN/htmledition/v2/images/webwxgetvideo.mp4'
				});
			}
		
		
		
			angular.extend(service, {
				isClientVersion:isClientVersion
			});
		
		
		
			return service;
		}]);
		})();
	
	
	/***/ }),
	/* 294 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/**
		 * module name:
		 * dependency:
		 *
		 */
		angular.module('Services')
		.factory('contactFactory', [
			'$rootScope',
			'$http', 
			'$q',
			'$timeout',
			'confFactory',
			'accountFactory',
			'emojiFactory',
			'utilFactory',
			'resourceService',
			'reportService',
				'mmHttp',
			function($rootScope,$http, $q,$timeout, confFactory,accountFactory,emojiFactory,utilFactory,resourceService,reportService, mmHttp) {
		
			var _contacts = window._contacts ={},
				_strangerContacts = window._strangerContacts = {},
				_allFriendContacts = [],
				_allStarContacts = [],
				_allChatroomContacts = [],
				_allBrandContacts = [],
				_chatRoomMemberDisplayNames = window._chatRoomMemberDisplayNames = {},
				_currentContact,
				_oReverseMap = {},
				_contactsToGetList = [],
				_contactsGettingList = [],
				_contactsWithErrorToGetList = [],
				_contactsGetErrMap = {},
				_remoteSearchCache = {},
				//_batchGetErrTokenMap = {},
				_batchGetContinuousErrCount = 0,
				_isBatchGetting = false,
				undefined,
				_readOnlyContacts = [
					'fmessage'//朋友推荐消息
				];
		
			/**
			 * 联系人操作扩展
			 */
			var _contactOperates = {
				/**
				 * 是否为自己
				 */
				isSelf : function () {
					return accountFactory.getUserName() == this.UserName; 
				},
				/**
				 * 是否为正常联系人
				 */
				isContact : function () {
					return !!(this.ContactFlag & confFactory.CONTACTFLAG_CONTACT) || this.UserName == accountFactory.getUserName();
				},
				/**
				 * 是否为黑名单联系人
				 */
				isBlackContact : function() {
					return !!(this.ContactFlag & confFactory.CONTACTFLAG_BLACKLISTCONTACT);
				},
				/**
				 * 是否为聊天联系人
				 */
				isConversationContact : function() {
					console.log("是否为聊天联系人")
					return !!(this.ContactFlag & confFactory.CONTACTFLAG_CHATCONTACT);
				},
				/**
				 * 是否为群聊
				 */
				isRoomContact : function() {
					return utilFactory.isRoomContact(this.UserName);
				},
				/**
				 * 是否为已删除群聊
				 */
				isRoomContactDel : function() {
					return this.isRoomContact() && !(this.ContactFlag & confFactory.CONTACTFLAG_CHATROOMCONTACT);
				},
				/**
				 * 是否自己是群聊群主
				 */
				isRoomOwner : function() {
					return this.isRoomContact() && this.IsOwner;
				},
				/**
				 * 是否为公众号
				 */
				isBrandContact : function(){
					return this.VerifyFlag & confFactory.MM_USERATTRVERIFYFALG_BIZ_BRAND;
				},
				/**
				 * 是否为为特殊联系人
				 */
				isSpContact : function() {
					return utilFactory.isSpUser(this.UserName);
				},
				/**
				 * 是否为屏蔽联系人
				 */
				isShieldUser : function() {
					var flag = utilFactory.isShieldUser(this.UserName) || (this.isRoomContact() && !this.isInChatroom());
	// 	            console.log(this)
					if(flag){ console.log('已屏蔽：',this.UserName,this.NickName); }
					return flag;
				},
				/**
				 * 是否为文件传输助手（特殊联系人）
				 */
				isFileHelper : function() {
					return this.UserName == confFactory.SP_CONTACT_FILE_HELPER;
				},
				/**
				 * 是否为文件传输助手（特殊联系人）
				 */
				isRecommendHelper : function() {
					return this.UserName == confFactory.SP_CONTACT_RECOMMEND_HELPER;
				},
				/**
				 * 是否为腾讯新闻（特殊联系人）
				 */
				isNewsApp : function() {
					return this.UserName == confFactory.SP_CONTACT_NEWSAPP;
				},
				/**
				 * 是否打开消息免打扰
				 */
				isMuted : function() {
					return this.isRoomContact() ? this.Statues === confFactory.CHATROOM_NOTIFY_CLOSE :
						this.ContactFlag & confFactory.CONTACTFLAG_NOTIFYCLOSECONTACT;
				},
				isTop : function() {
					return this.ContactFlag & confFactory.CONTACTFLAG_TOPCONTACT;
				},
				/**
				 * 是否有朋友圈相册
				 */
				hasPhotoAlbum : function(){
					return this.SnsFlag & 1;
				},
				isInChatroom: function () {
					var me = this;
		
					if(this.MemberList.length == 0 && this.ContactFlag != 0){
						return true;
					}
		
					if(me.MMInChatroom === false || me.MMInChatroom === true){
						return me.MMInChatroom;
					}
		
					angular.forEach(this.MemberList,function (item) {
						if(item.UserName == accountFactory.getUserInfo().UserName){
							me.MMInChatroom = true;
							return;
						}
					});
					me.MMInChatroom = me.MMInChatroom || false;
					return me.MMInChatroom;
		
				},
				isReadOnlyContact: function () {
					return _readOnlyContacts.indexOf(this.UserName) > -1;
				},
				/**
				 * 获取联系人`DisplayName`
				 * @param chatroomUserName 可选
				 */
				getDisplayName: function (chatroomUserName) {
					var me = this,
						displayName = "";
		
					if (utilFactory.isRoomContact(me.UserName)) {
						displayName = me.RemarkName || me.NickName;
						if (!displayName && me.MemberList) {
							for (var i = 0,len = me.MemberList.length; i < len && i < 10; ++i) {
								if (displayName.length > 0) displayName += ", ";
								var roomMember = me.MemberList[i],
									roomMemberFriend = service.getContact(roomMember.UserName);
		
								displayName += (roomMemberFriend && roomMemberFriend.RemarkName) /*|| roomMember.getDisplayName()*/ || (roomMemberFriend && roomMemberFriend.NickName) || roomMember.NickName;
							}
						} else if (!displayName) {
							displayName = me.UserName;
						}
					} else {
						displayName = me.RemarkName || (chatroomUserName && chatroomUserName != me.UserName && me.getMemberDisplayName(chatroomUserName)) || me.NickName;
					}
					return displayName;
				},
				getMemberDisplayName: function (chatroomUserName) {
					var chatroomId = service.getChatroomIdByUserName(chatroomUserName);
					if(chatroomUserName && _chatRoomMemberDisplayNames[chatroomUserName]){
						return _chatRoomMemberDisplayNames[chatroomUserName][this.UserName];
					}else{
						return '';
					}
				},
				chatroomCanSearch : function(keyword) {
					if (this.isRoomContact()) {
						if(this.canSearch(keyword)){
							return true;
						}else{
							for (var i=0,len=this.MemberList.length; i<len; i++) {
								var _sUserName = this.MemberList[i].UserName,
									_oMember = service.getContact(_sUserName);
								if (_oMember && _oMember.canSearch(keyword)) {
									return true;
								}
							}
						}
		
					}
				},
				/**
				 * 是否可以通过某关键字检索
				 * @param  {[type]} keyword
				 * @param  {[type]} _abContainChatroomMembers [description]
				 * @return {[type]}                           [description]
				 */
				canSearch : function(keyword, _abContainChatroomMembers) {
					if (!keyword) {
		
						return true;
					}
		
					keyword = keyword.toUpperCase();
					var remarkName = this.RemarkName || '';
					var remarkPYQuanPin = this.RemarkPYQuanPin || '';
					var nickName = this.NickName || '';
					var PYQuanPin = this.PYQuanPin  || '';
					var alias = this.Alias || '';
					var userKeyWord = this.KeyWord || '';
					var a=0, b=0;
					a = remarkName.toUpperCase().indexOf(keyword);
					b = remarkPYQuanPin.toUpperCase().indexOf(keyword);
					if (a >= 0 || b>=0) {
		
						return true;
					} 
		
					a = nickName.toUpperCase().indexOf(keyword);
					b = PYQuanPin.toUpperCase().indexOf(keyword);
					if (a >= 0 || b >= 0) {
		
						return true;
					}
					
					if (alias.toUpperCase().indexOf(keyword)>=0) {
		
						return true;
					}
		
					if(userKeyWord.toUpperCase().indexOf(keyword)>=0){
						return true;
					}
		
					return false;
				},
		
				update : function(_aoOptions) {
					if (_aoOptions) {
						angular.extend(this, _aoOptions);
					}
				}
			};
		
			/**
			 * 扩展联系人对象
			 */
			function _extendContact(contact) {
				contact = angular.extend({
					RemarkPYQuanPin:"",
					RemarkPYInitial:"",
					PYInitial:"",
					PYQuanPin:""
				}, contact, _contactOperates);
				if(!contact.HeadImgUrl){
					contact.HeadImgUrl = confFactory.API_webwxgeticon + '?seq=0&username='+contact.UserName +'&skey='+accountFactory.getSkey();
				}
				return contact;
			}
		
			var service = {
				contactChangeFlag: '',
				setCurrentContact: function (contact) {
					_currentContact = contact;
				},
				getCurrentContact: function () {
					return _currentContact;
				},
		
				/**
				 * 判断`userName`是否当前登录用户
				 * @param userName - userName
				 * @returns {boolean} - true：传入的`userName`为当前登录用户；false: 传入的`userName`不是当前登录用户
				 */
				isSelf : function (userName) {
					return accountFactory.getUserName() == userName; 
				},
		
				/**
				 * 从服务器获取全部联系人，返回`Promise`对象
				 * @returns {Promise}
				 */
				initContact:function (seq) {
					var deferred = $q.defer();
					$http({
						method:'GET',
						url:confFactory.API_webwxgetcontact,
						params:{
							skey:accountFactory.getSkey(),
							pass_ticket:accountFactory.getPassticket(),
							seq: seq,
							r:utilFactory.now()
						}
					}).success(function(data){
						deferred.resolve(data);
					}).error(function(data){
						deferred.reject('error:'+data);
		
						reportService.report(reportService.ReportType.netError,{
							text:'init contact',
							url:confFactory.API_webwxgetcontact,
							params:{
								skey:accountFactory.getSkey(),
								pass_ticket:accountFactory.getPassticket()
							}
						})
					});
					return deferred.promise;
				},
				/**
				 * 联系人预处理
				 */
				specialContactHandler:function (contact) {
					var needModifyNickNameMap = {
						"weixin":_("6c2fc35"),
						"filehelper":_("eb7ec65"),
						"newsapp":_("0469c27"),
						"fmessage": _("a82c4c4")
					};
					// 部分微信内建联系人重新设置NickName
					if(needModifyNickNameMap[contact.UserName]){
						contact.NickName = needModifyNickNameMap[contact.UserName];
					}
					//
					if (contact.UserName == "fmessage") {
						contact.ContactFlag = 0;
					}
					return contact;
				},
				addContact:function(contact){
					if(!contact) return;
					if(!contact.isContact){
						contact = _extendContact(contact);
						contact.MMOrderSymbol = this.getContactOrderSymbol(contact);
					}
					if (contact.EncryChatRoomId && contact.UserName) {
						contact.MMFromBatchget = true;
					}
		
		
					contact.RemarkName = contact.RemarkName && emojiFactory.transformSpanToImg(contact.RemarkName);
					contact.NickName =  contact.NickName &&emojiFactory.transformSpanToImg(contact.NickName);
		
		
					if(!contact.isShieldUser() && (contact.isContact() || contact.isRoomContact())){
						this.addFriendContact(contact);
					}else{
						this.addStrangerContact(contact);
					}
				},
				/**
				 * 添加好友联系人
				 */
				addFriendContact:function (contact) {
					var me = this,
						oldContact;
					if (!contact/* || utilFactory.isShieldUser(contact.UserName)*/) return;
		
					contact = me.specialContactHandler(contact);
					oldContact = _contacts[contact.UserName];
					if(oldContact){
						for(var attr in contact){
							if(!contact[attr]){
								delete contact[attr];
							}
						}
						angular.extend(oldContact, contact);
					}else{
						//contact = _extendContact(contact);
						//if(contact.isShieldUser() || (!contact.isRoomContact() && !contact.NickName)) return;
						//contact.MMDisplayName = me.getContactDisplayName(contact);
						//contact.MMOrderSymbol = me.getContactOrderSymbol(contact);
						_contacts[contact.UserName] = contact;
						//if(contact.isRoomContact()) console.log('addContact chatroom:',contact.UserName,contact.MMDisplayName);
					}
					//
					me.contactChangeFlag = +new Date;
		
		
					resourceService.load({
						url:contact.HeadImgUrl,
						type:'image'
					});
				},
				addContacts:function (contacts,isFromBatchGet) {
					var me = this;
		
					angular.forEach(contacts,function (contact,index) {
						if(isFromBatchGet){
							contact.MMFromBatchGet = true;
						}
						me.addContact(contact);
						/*if (contact.ChatRoomId && contact.UserName) {
							me.addStrangerContact(contact);
							contact.MMFromBatchget = true;
						}else{
							me.addContact(contact);
						}*/
		
					});
		
				},
				/**
				 * 删除联系人，变为陌生人联系人
				 * @param  {[type]} userName
				 * @param  {[type]} contactFlag
				 */
				deleteContact: function (deleteContact) {
					var contact = this.getContact(deleteContact.UserName);
					if(contact){
						delete _contacts[deleteContact.UserName];
						angular.extend(contact,deleteContact);
						_strangerContacts[deleteContact.UserName] = contact;
					}
				},
				/**
				 * 根据`userName`获取联系人
				 * @param userName - 联系人名称
				 * @param chatroomId
				 * @returns {*}
				 */
				getContact: function(userName,chatroomUserName,noBatchGet) {
					var me = this,contact,chatroomId;
		
					contact = _contacts[userName];
					if(!contact){
						contact = me.getStrangerContacts(userName)
					}
					if(noBatchGet) return contact;
		
					if(!contact || (utilFactory.isRoomContact(userName) && contact.MemberList.length == 0)/* || (chatroomUserName && contact._getMemberDisplayName(chatroomUserName) === undefined)*/){
					  //  chatroomId = me.getChatroomIdByUserName(chatroomUserName);
						me.addBatchgetContact({
							UserName:userName,
							EncryChatRoomId:chatroomUserName||""
						});
					}
					return contact;
				},
				/**
				 * 获取陌生人联系人信息
				 * @param  userName
				 */
				getStrangerContacts: function (userName) {
					return _strangerContacts[userName];
				},
				/**
				 * 添加陌生人联系人信息
				 * @param  userName
				 */
				addStrangerContact: function (contact) {
					var me = this,oldContact;
		
					oldContact = _strangerContacts[contact.UserName];
					if(oldContact){
						for(var attr in contact){
							if(!contact[attr]){
								delete contact[attr];
							}
						}
						angular.extend(oldContact, contact);
					}else {
						//contact = _extendContact(contact);
						//contact.MMDisplayName = me.getContactDisplayName(contact);
						//contact.MMOrderSymbol = me.getContactOrderSymbol(contact);
						_strangerContacts[contact.UserName] = contact;
					}
		
					resourceService.load({
						url:contact.HeadImgUrl,
						type:'image'
					});
				},
				/**
				 * 添加群成员DisplayName，用于读取群成员昵称`DisplayName`
				 * @param contact
				 */
				addChatroomMemberDisplayName: function (contact, chatroomUserName) {
					if(!contact.DisplayName) return;
		
					if(chatroomUserName){
						if(!_chatRoomMemberDisplayNames[chatroomUserName]){
							_chatRoomMemberDisplayNames[chatroomUserName] = {};
						}
						_chatRoomMemberDisplayNames[chatroomUserName][contact.UserName] = contact.DisplayName;
					}
				},
				getChatroomIdByUserName: function (chatroomUserName) {
					var chatroomContact = _contacts[chatroomUserName] || {};
					return chatroomContact.EncryChatRoomId;
				},
				inContactsWithErrorToGetList: function(userObj){
					for(var i=0,len=_contactsWithErrorToGetList.length;i<len;i++){
						if(_contactsWithErrorToGetList[i].UserName == userObj.UserName){
							return i;
						}
					}
					return -1;
				},
				inContactsToGetList:function (userObj) {
					for(var i=0,len=_contactsToGetList.length;i<len;i++){
						if(_contactsToGetList[i].UserName == userObj.UserName){
							return i;
						}
					}
					return -1;
				},
				inContactsGettingList:function (userObj) {
					for(var i=0,len=_contactsGettingList.length;i<len;i++){
						if(_contactsGettingList[i].UserName == userObj.UserName){
							return i;
						}
					}
					return -1;
				},
				inContactsGetErrMap: function (userObj) {
					return _contactsGetErrMap[userObj.UserName];
				},
				/**
				 * 添加到批量获取联系人列表
				 */
				addBatchgetContact:function (userObj,isBatchNow,isHadBathGetErrorOnce) {
					var deferred = $q.defer(),me = this,tmpIndex,doBatchGetTimer;
		
					if(!userObj || !userObj.UserName) return;
		
					if(isHadBathGetErrorOnce){
						if(me.inContactsWithErrorToGetList(userObj)>-1){
							return;
						}else{
							_contactsWithErrorToGetList.push(userObj);
							tmpIndex = me.inContactsToGetList(userObj)
							if(tmpIndex>-1){
								_contactsToGetList.splice(tmpIndex,1);
							}
						}
					}else{
						if(me.inContactsToGetList(userObj)>-1 || me.inContactsGettingList(userObj)>-1 || me.inContactsGetErrMap(userObj)) return;
						// 优先获取群聊联系人信息
						if(utilFactory.isRoomContact(userObj.UserName) || isBatchNow){
							_contactsToGetList.unshift(userObj);
						}else{
							_contactsToGetList.push(userObj);
						}
					}
					
		
					doBatchGetTimer && $timeout.cancel(doBatchGetTimer);
					// 等待200ms再batchget，减少batchget次数
					doBatchGetTimer = $timeout(function () {
						if(!_contactsGettingList.length && (_contactsToGetList.length || _contactsWithErrorToGetList.length)){
							me.batchGetContact().then(addContactsHandler,batchGetContactErrorHandler);
						}
					},200);
					function addContactsHandler (data) {
						deferred.resolve(data.ContactList);
						_batchGetContinuousErrCount = 0;
						//console.log('batchGetContact',data);
						/*angular.forEach(_contactsGettingList,function (item,index) {
							if(_contactsGetErrMap[item.UserName]){
								_contactsGetErrMap[item.UserName] = _contactsGetErrMap[item.UserName] + 1;
							}else{
								_contactsGetErrMap[item.UserName] = 1;
							}
						});*/
		
		
						// add chatroom member contact
						// add chatroom member displayName
						console.time('addContactsHandler');
						angular.forEach(data.ContactList,function (contact) {
							var tmpIndex = me.inContactsToGetList({UserName:contact.UserName});
							if(tmpIndex>-1){
								_contactsToGetList.splice(tmpIndex,1);
							}
							if(utilFactory.isRoomContact(contact.UserName) && contact.MemberList && contact.MemberList.length){
								angular.forEach(contact.MemberList,function (item) {
									var c = me.getContact(item.UserName,'',true);
									if(!c || !c.isContact()){
										// batchget member contact no HeadImgUrl
										item.HeadImgUrl = utilFactory.getContactHeadImgUrl({
											EncryChatRoomId:contact.EncryChatRoomId,
											UserName:item.UserName,
											Skey:accountFactory.getSkey()
										});
										me.addContact(item);
									}
									me.addChatroomMemberDisplayName(item,contact.UserName);
									//remove current batchget member from _contactsToGetList
									var index = me.inContactsToGetList({UserName:item.UserName});
									if(index > -1){
										_contactsToGetList.splice(index,1);
									}
								});
							}else{
								me.addChatroomMemberDisplayName(contact,contact.UserName);
							}
						});
		
		
						console.timeEnd('addContactsHandler');
						me.addContacts(data.ContactList,true);
		
						//test
						/*angular.forEach(data.ContactList,function (contact) {
							if(utilFactory.isRoomContact(contact.UserName)){
								console.log('batchGetContact chatroom',contact.UserName,contact.NickName);
							}
						})*/
						//test end
						_contactsGettingList = [];
						if(!_contactsGettingList.length && _contactsToGetList.length >0){
							me.batchGetContact().then(addContactsHandler,batchGetContactErrorHandler);
						}
					}
					function batchGetContactErrorHandler (errorToken) {
						var tmpGettingList = _contactsGettingList;
						_contactsGettingList = [];
						_batchGetContinuousErrCount++;
						deferred.reject(errorToken);
						if(tmpGettingList.length == 1){
							console.log('batchGetContactError',tmpGettingList[0]);
							_contactsGetErrMap[tmpGettingList[0].UserName] = 1;
						}else{
							angular.forEach(tmpGettingList, function (item) {
								//console.log('batchGetContactErrorHandler push',item);
								me.addBatchgetContact(item,false,true);
							});
						}
						if(!_contactsGettingList.length && (_contactsToGetList.length || _contactsWithErrorToGetList.length)){
							me.batchGetContact().then(addContactsHandler,batchGetContactErrorHandler);
						}
		
						/*console.error('batchGetContactErrorHandler',errorToken);
						if(!_batchGetErrTokenMap[errorToken]){
							_batchGetErrTokenMap[errorToken] = 1;
						}
						if( _batchGetErrTokenMap[errorToken] > 2){
							console.error('batchGetContactErrorHandler max',errorToken);
							_contactsGettingList = [];
							if(!_contactsGettingList.length && _contactsToGetList.length >0){
								me.batchGetContact().then(addContactsHandler,batchGetContactErrorHandler);
							}
						}else{
							_batchGetErrTokenMap[errorToken] += 1;
							me.batchGetContact(errorToken).then(addContactsHandler,batchGetContactErrorHandler);
						}*/
					}
					return deferred.promise;
				},
				addBatchgetChatroomContact:function (userName) {
					if(!utilFactory.isRoomContact(userName)) return;
					
					var contact = this.getContact(userName);
					if(!contact || !contact.MMFromBatchGet){
						this.addBatchgetContact({
							UserName:userName,
							ChatRoomId:""
						});
					}
				},
				/**
				 * batchget群成员
				 * @param userName
				 */
				addBatchgetChatroomMembersContact:function(userName){
					var me = this,
						chatroomContact = me.getContact(userName);
		
					if(chatroomContact && chatroomContact.isRoomContact() && !chatroomContact.MMBatchgetMember && chatroomContact.MemberList.length > 0){
						chatroomContact.MMBatchgetMember = true;
						angular.forEach(chatroomContact.MemberList,function(item){
							var memberContact = me.getContact(item.UserName);
							if(memberContact && !memberContact.isContact() && !memberContact.MMFromBatchget){
								me.addBatchgetContact({
									UserName:memberContact.UserName,
									EncryChatRoomId:chatroomContact.UserName
								});
							}
						});
					}
				},
				/**
				 * 批量获取联系人信息
				 */
				batchGetContact: function (errorToken) {
					var deferred = $q.defer(),
						contactsWithErrorToGetStep = 1,
						me = this;
		
					if(_contactsWithErrorToGetList.length){
						if(_contactsWithErrorToGetList.length < 6 || _batchGetContinuousErrCount > 2){
							contactsWithErrorToGetStep = 1
						}else if(_contactsWithErrorToGetList.length < 40){
							contactsWithErrorToGetStep = 5
						}else{
							contactsWithErrorToGetStep = 10
						}
						_contactsGettingList = _contactsWithErrorToGetList.splice(0, contactsWithErrorToGetStep);
						console.log('_contactsWithErrorToGetList lenght:',_contactsWithErrorToGetList.length);
					}else{
						_contactsGettingList = _contactsToGetList.splice(0, 50);
					}
		
					$http({
						method:"POST",
						url:confFactory.API_webwxbatchgetcontact + '?type=ex&r='+utilFactory.now(),
						data:angular.extend(accountFactory.getBaseRequest(),{
							Count:_contactsGettingList.length,
							List:_contactsGettingList
						})
					}).success(function(data){
						if(data && data.BaseResponse && data.BaseResponse.Ret == 0){
							deferred.resolve(data);
						}else{
							console.log('batchGetContact data.BaseResponse.Ret =',data.BaseResponse.Ret);
							deferred.reject(errorToken);
						}
					}).error(function(data){
						reportService.report(reportService.ReportType.netError,{
							text:'batchGetContact',
							url:confFactory.API_webwxbatchgetcontact
						})
						deferred.reject(errorToken);
					});
					return deferred.promise;
				},
				// 不再单独batchGet群用户，直接batchGet chatroom，这样回直接返回群聊用户displayName
				/*batchGetChatroomMembersContact: function (userName) {
					var me = this,chatRoom;
					chatRoom = me.getContact(userName);
					if(chatRoom && chatRoom.MemberList){
						if(chatRoom.MemberList.length){
							angular.forEach(chatRoom.MemberList,function (item) {
								me.getContact(item.UserName,chatRoom.UserName);
							});
						}else{
							// MemberList.length = 0
							me.addBatchgetContact({
								UserName:userName,
								ChatRoomId:""
							});
						}
					}
				},*/
				/**
				 * 根据`群名称`获取群成员列表
				 * @param userName
				 * @param withoutMe 是否排除自己
				 * @returns {Array}
				 */
				getChatRoomMembersContact:function (userName, withoutMe) {
					var that = this,
						chatRoom = _contacts[userName],
						chatRoomMembersContact = [],
						waitBatchGetContactList = [];
		
					if(chatRoom){
						angular.forEach(chatRoom.MemberList,function (item) {
							var tmpContact = that.getContact(item.UserName);
							if(!tmpContact){
								tmpContact = item;
							}
							if(!(withoutMe && tmpContact.UserName == accountFactory.getUserName())){
								chatRoomMembersContact.push(tmpContact);
							}
						});
						return chatRoomMembersContact;
					}else{
						return [];
					}
				},
				/**
				 * 获取全部联系人
				 * @returns {{Array}}
				 */
				getAllContacts: function() {
					return _contacts;
				},
		
				/**
				 * 获取全部星标联系人
				 * @returns {Array}
				 */
				getAllStarContact:function (options) {
					options = options || {};
		
					var contacts;
					if(options.isNewArray){
						contacts = [];
					}else{
						contacts = _allStarContacts;
					}
					contacts.length = 0;
		
					var filterContacts = options.filterContacts || {};
		
					for (var name in _contacts) {
						var _contact = _contacts[name];
						if (!_contact.isSelf() && _contact.StarFriend == 1 && !filterContacts[name] &&_contact.canSearch(options.keyword)) {
							contacts.push(_contact);
						}
					}
		
					contacts = contacts.sort(function(_oC1, _oC2){
						return _oC1.MMOrderSymbol > _oC2.MMOrderSymbol ? 1 : -1;
					});
		
					return contacts;
				},
				/**
				 * 获取全部群组
				 * options.isNewArray 是否产生新数组，避免多个地方使用同一个数组互相影响，但有不及时双向绑定问题
				 * options.isSaved 是否保存到通讯录里面的群组
				 * @returns {Array}
				 */
				getAllChatroomContact : function(options) {
					options = options || {};
		
					var contacts;
					if(options.isNewArray){
						contacts = [];
					}else{
						contacts = _allChatroomContacts;
					}
					contacts.length = 0;
					var filterContacts = options.filterContacts || {};
					for (var name in _contacts) {
						var contact = _contacts[name];
						if (contact.isRoomContact() && (!options.keyword || contact.chatroomCanSearch(options.keyword)) && !filterContacts[name] ) {
							if(options.isSaved && !contact.isContact()) continue; // 筛选通讯录里的群组
							contacts.push(contact);
						}
					}
					contacts.sort(function(_oC1, _oC2){
						return _oC1.MMOrderSymbol > _oC2.MMOrderSymbol ? 1 : -1;
					});
		
		
					return contacts;
				},
				/**
				 * 获取所有公众号列表
				 * @param  {[type]} keyword [description]
				 * @return {[type]}         [description]
				 */
				getAllBrandContact: function (options) {
					options = options || {};
		
					var contacts;
					if(options.isNewArray){
						contacts = [];
					}else{
						contacts = _allBrandContacts;
					}
					contacts.length = 0;
		
					for (var name in _contacts) {
		
						var contact = _contacts[name];
						if (!contact.isBrandContact()) {
							continue;
						}
		
						if (contact.canSearch(options.keyword)) {
							contacts.push(contact);
						}
					}
		
					contacts.sort(function(_oC1, _oC2){
						return _oC1.MMOrderSymbol > _oC2.MMOrderSymbol ? 1 : -1;
					});
		
					return contacts;
				},
				/**
				 * 获取好友联系人列表
				 * @param  {object} options
				 * @param  options.keyword
				 * @param  options.isNewArray       //是否产生新数组，避免多个地方使用同一个数组互相影响，但有不及时双向绑定问题
				 * @param  options.filterContacts   //过滤联系人列表
				 * @param  options.isWithoutStar      //是否排查标星好友
				 * @param  options.isWithoutBrand   //是否排除公众号
				 */
				getAllFriendContact : function(options) {
					options = options || {};
		
					var contacts;
					if(options.isNewArray){
						contacts = [];
					}else{
						contacts = _allFriendContacts;
					}
					contacts.length = 0;
					options.filterContacts = options.filterContacts || {};
					for (var name in _contacts) {
						if (options.filterContacts[name]) {
							continue;
						}
		
						var contact = _contacts[name];
						if ((contact.isSelf() && !accountFactory.isHigherVer()) || !contact.isContact() ||
							options.isWithoutStar && contact.StarFriend == 1 ||
							contact.isRoomContact() ||
							options.isWithoutBrand && contact.isBrandContact() ||
							contact.isShieldUser()) {
							//console.log('filter',contact.MMDisplayName);
							continue;
						}
		
						if (contact.canSearch(options.keyword)) {
							 contacts.push(contact);
						}
					}
		
					contacts.sort(function(_oC1, _oC2){
						return _oC1.MMOrderSymbol > _oC2.MMOrderSymbol ? 1 : -1;
					});
		
					/*contacts.sort(function(_oC1, _oC2){
						if(_oC1.MMOrderSymbol.charAt(0) != _oC2.MMOrderSymbol.charAt(0)){
							_oC1.MMC = _oC1.MMOrderSymbol.charAt(0);
						}
						return false;
					});*/
		
					return contacts;
				},
		
				/**
				 *
				 * @param keywork
				 * @return promise
				 */
				remoteSearch:function(keyword){
					var deferred = $q.defer();
					this.prevSearchCanceler && this.prevSearchCanceler.resolve();
					this.prevSearchCanceler = $q.defer();
					if(_remoteSearchCache[keyword]){
						deferred.resolve(getContact(_remoteSearchCache[keyword]));
					}else{
						$http({
							method:"POST",
							url:confFactory.API_webwxsearch,
							timeout: this.prevSearchCanceler.promise,
							data:angular.extend(accountFactory.getBaseRequest(),{KeyWord: keyword})
						}).success(function(data){
							if(data.BaseResponse && data.BaseResponse.Ret == 0){
								var list = data.List;
		
								if(list.length>0){
									_remoteSearchCache[keyword] = list;
								}
		
								deferred.resolve(getContact(list));
							}else{
								//deferred.reject(data);
							}
						}).error(function(data){
							//deferred.reject(data);
						});
					}
		
		
		
		
					return deferred.promise;
		
					function getContact(list){
						var username,user,result=[];
						for(var i =0;i<list.length;i++){
							username = list[i].EncryUserName;
							user =_contacts[username];
		
							if(user && user.isContact() && !user.isBrandContact()) result.push(user);
						}
						return result;
					}
				},
				pickContacts:function(pickList,opt,clone){
					var composeContacts = [];
					var self = this,pickItem,tmp,optConf;
					var allConfig = opt['all'] || {};
					for(var i = 0;i < pickList.length;i++){
						pickItem = pickList[i];
						optConf = opt[pickItem] || {};
						optConf = $.extend({},optConf,allConfig);
						switch (pickItem){
							case 'star':
								tmp = self.getAllStarContact(optConf);
								if(tmp.length > 0){
									optConf.noHeader || composeContacts.push({
										text:_("f13fb20"),
										type:'header'
									});
									[].push.apply(composeContacts,tmp);
								}
		
								;break;
							case 'friend':
								tmp = self.getAllFriendContact(optConf);
								if(tmp.length > 0){
									optConf.showFriendHeader && composeContacts.push({
										text:_("59d29a3"),
										type:'header'
									});
									var currentOrderSymbol = '';
		
									optConf.showFriendHeader || optConf.noHeader || angular.forEach(tmp,function (item,index) {
										if(!item.MMOrderSymbol) return;
										var orderSymbol = item.MMOrderSymbol.charAt(0);
										if(currentOrderSymbol!=orderSymbol){
											currentOrderSymbol = orderSymbol;
											tmp.splice(index,0,{text:orderSymbol,type:'header'});
										}
									});
									[].push.apply(composeContacts,tmp);
								}
								;break;
							case 'chatroom':
								tmp = self.getAllChatroomContact(optConf);
								if(tmp.length > 0){
									optConf.noHeader || composeContacts.push({
										text:_("4b0ab7b"),
										type:'header'
									});
									[].push.apply(composeContacts,tmp);
								}
								;break;
							case 'brand':
								tmp = self.getAllBrandContact(optConf);
								if(tmp.length > 0){
									opt[pickItem].noHeader || composeContacts.push({
										text:_("215feec"),
										type:'header'
									});
									[].push.apply(composeContacts,tmp);
								}
								;break;
						}
					}
		
					if(clone){
						composeContacts = angular.copy(composeContacts);
					}
		
					return {
						result:composeContacts
					}
				},
		
				/**
				 * 获取联系人排序符号
				 */
				getContactOrderSymbol: function (contact) {
					if (!contact) return '';
					var orderSymbol = '';
					orderSymbol = utilFactory.clearHtmlStr(contact.RemarkPYQuanPin || contact.PYQuanPin || contact.NickName || "").toLocaleUpperCase().replace(/\W/ig, "");
		
					if (orderSymbol.charAt(0) < 'A') {
						orderSymbol = "~";
					}
					return orderSymbol;
				},
				verifyUser: function (options) {
					var deferred = $q.defer(),
						me = this;
					var params = {
						Opcode: options.Opcode || confFactory.VERIFYUSER_OPCODE_VERIFYOK,
						VerifyUserListSize:1,
						VerifyUserList:[{Value:options.UserName,VerifyUserTicket:options.Ticket||''}],
						VerifyContent:options.VerifyContent||'',
						SceneListCount:1,
						SceneList:[options.Scene],
						skey:accountFactory.getSkey()
					};
					$http({
						method:"POST",
						url:confFactory.API_webwxverifyuser + '?r='+utilFactory.now(),
						data:angular.extend(accountFactory.getBaseRequest(),params)
					}).success(function(data){
						if(data.BaseResponse && data.BaseResponse.Ret == 0){
							deferred.resolve(data);
						}else{
							deferred.reject(data);
		
							reportService.report(reportService.ReportType.netError,{
								text:'添加验证好友，服务器返回错误',
								url:confFactory.API_webwxverifyuser,
								params:params,
								res:data
							})
						}
					}).error(function(data){
						deferred.reject(data);
						reportService.report(reportService.ReportType.netError,{
							text:'添加验证好友，请求失败',
							url:confFactory.API_webwxverifyuser,
							params:params,
							res:data
						})
					});
		
					return deferred.promise;
				},
				setTopContact:function(username,top){
					var contact = this.getContact(username)
		
					if(top){
						contact.ContactFlag = contact.ContactFlag|confFactory.CONTACTFLAG_TOPCONTACT;
					}else{
						contact.ContactFlag = contact.ContactFlag&~confFactory.CONTACTFLAG_TOPCONTACT;
					}
					$rootScope.$broadcast('contact:settop',contact);
		
					mmHttp({
						method:"POST",
						url:confFactory.API_webwxoplog,
						data:angular.extend({
							UserName:username,
							CmdId:confFactory.oplogCmdId.TOPCONTACT,
							OP:top?1:0,
							RemarkName:contact.RemarkName
						}, accountFactory.getBaseRequest()),
						MMRetry:{
							count:3,
							timeout:10000,
							serial:true
						}
					}).success(function(data){
		
					}).error(function(data){
		
					});
				}
			};
			return service;
		}]);
		})();
	
	
	/***/ }),
	/* 295 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('loginFactory', ['$http', '$q','$timeout', 'accountFactory', 'confFactory', 'utilFactory','mmHttp','reportService', function($http, $q, $timeout, accountFactory, confFactory,utilFactory,mmHttp,reportService) {
			var service = {
				getUUID: function () {
					var deferred = $q.defer();
					window.QRLogin = {};
					// ie8
					$.ajax({
						url: confFactory.API_jsLogin,
						dataType : "script",
						timeout : 10000
					}).done(function() {
						if(window.QRLogin.code==200){
							deferred.resolve(window.QRLogin.uuid);
						}else{
							deferred.reject(window.QRLogin.code);
						}
					}).fail(function(){
						deferred.reject();
						console.log('get uuid fail.....');
					});
					/*$http.jsonp(confFactory.API_jsLogin).success(function(data){
						//not standard jsonp, call error handler.
					}).error(function(data){
						if(window.QRLogin.code==200){
							deferred.resolve(window.QRLogin.uuid);
						}else{
							deferred.reject(window.QRLogin.code);
						}
					});*/
					return deferred.promise;
				},
				getQrcode: function (argument) {
					// body...
				},
				checkLogin: function (uuid,tip) {
					var deferred = $q.defer(),
						tip = tip || 0;
					window.code = 0;
					// ie8
					window.checkLoginPromise = $.ajax({
						url: confFactory.API_login+'?loginicon=true&uuid='+uuid+'&tip='+tip+'&r='+~new Date(),
						dataType : "script",
						timeout : 35000
					}).done(function() {
						var reg = new RegExp('\/'+location.host+'\/')
		
						if(window.redirect_uri && window.redirect_uri.indexOf('/'+location.host+'/') < 0){
							location.href = window.redirect_uri;
							return;
						}
						var data = {
							code:window.code,
							redirect_uri:window.redirect_uri,
							userAvatar:window.userAvatar
						};
						deferred.resolve(data);
					}).fail(function(){
						deferred.reject();
						console.log('checkLogin fail.....');
					});
					/*$http.jsonp(confFactory.API_login+'?loginicon=true&uuid='+uuid+'&tip='+tip+'&r='+~new Date(),{timeout:35000}).success(function(data){
						//not standard jsonp, call error handler.
					}).error(function(data){
						var reg = new RegExp('\/'+location.host+'\/')
		
						if(window.redirect_uri && window.redirect_uri.indexOf('/'+location.host+'/') < 0){
							location.href = window.redirect_uri;
							return;
						}
						var data = {
							code:window.code,
							redirect_uri:window.redirect_uri,
							userAvatar:window.userAvatar
						};
						deferred.resolve(data);
					});*/
					return deferred.promise;
				},
				/**
				 * 关联登录
				 * @param uin
				 */
				associationLogin: function (uin){
					var deferred = $q.defer();
					var url = confFactory.API_webwxpushloginurl + '?uin=' + encodeURIComponent(uin);
					console.log('associationLogin: ', url);
		
					if(confFactory.isClientVersion){
						url = url + '&mod=desktop';
					}
		
		
					$.ajax({
						url: url,
						dataType: 'json'
					}).done(function (res){
						// {"ret":0,"msg":all ok,"uuid"：dfds34343}
						if(res.ret == 0){
							deferred.resolve(res);
						}
						else {
							deferred.reject(res);
						}
					}).fail(function (){
						deferred.reject();
					});
		
					return deferred.promise;
				},
				newLoginPage: function (redirect_uri) {
		
				  let url = redirect_uri+"&fun=new&version=v2";
		
				  if(confFactory.isClientVersion){
					url = url + '&mod=desktop';
				  }
		
		
					var deferred = $q.defer();
					mmHttp({
						method:"GET",
						url:url,
						MMRetry:{
							count:3,
							timeout:10000,
							serial:true
						}
					}).success(function(data){
						reportService.report(reportService.ReportType.timing,{
							timing:{
								loginEnd:Date.now()
							}
						});
						deferred.resolve(data);
					}).error(function(data){
						deferred.reject('error:'+data);
					});
					return deferred.promise;
				},
				loginout: function (type) {
					window.onbeforeunload = null;
					var url = confFactory.API_webwxlogout + "?redirect=1&type=" + (type||0)+"&skey="+encodeURIComponent(accountFactory.getSkey());
					utilFactory.form(url,{
						sid : accountFactory.getSid(),
						uin : accountFactory.getUin()
					});
				},
				timeoutDetect:function(code){
					/*MMWEBWX_OK = 0 ,
					 MMWEBWX_ERR_SYS = -1 ,
					 MMWEBWX_ERR_LOGIC = -2 ,
					 MMWEBWX_ERR_SESSION_NOEXIST = 1100,
					 MMWEBWX_ERR_SESSION_INVALID = 1101,
					 MMWEBWX_ERR_PARSER_REQUEST = 1200,
					 MMWEBWX_ERR_FREQ = 1205 // 频率拦截
					 */
					code = (+code);
					if (code == 1100) {
						window.onbeforeunload = null;
						this.loginout(0);
		
						return true;
		
					} else if (code == 1101 || code == 1102) {
						window.onbeforeunload = null;
						this.loginout(0);
		
						return true;
					} else if(code == 1205){
						this.loginout(1);
					}
				}
			};
			return service;
		}]);
		})();
	
	
	/***/ }),
	/* 296 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('utilFactory', [ '$q','$rootScope','confFactory',function( $q ,$rootScope, confFactory) {
		
			window.isFocus = true; // 当前window是否聚焦
			var shareObjects = {};
			var _voicePlayer;
			var _checkURLsuffix; // 获取checkurl时需要传参，但是参数需要用到accountFactory的数据，所以这里延迟赋值
			var _urlReg =  "(\\s|\\n|<br>|^)(http(s)?://.)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?(&|&amp;)//=]*)";
		
			/**
			 * 特殊用户列表，not to insert in first
			 */
			var _SpUsersList = [
				"weibo",
				"qqmail",
				"fmessage",
				"tmessage",
				"qmessage",
				"qqsync",
				"floatbottle",
				"lbsapp",
				"shakeapp",
				"medianote",
				"qqfriend",
				"readerapp",
				//"newsapp",
				"blogapp",
				"facebookapp",
				"masssendapp",
				"meishiapp",
				"feedsapp",
				"voip",
				"blogappweixin",
				"weixin",
				"brandsessionholder",
				"weixinreminder",
				"wxid_novlwrv3lqwv11",
				"gh_22b87fa7cb3c",
				"officialaccounts",
				"notification_messages"
			];
			/**
			 * 屏蔽用户列表，not to show them
			 */
			var _shieldUsersList = [
				"newsapp",//临时屏蔽腾讯新闻
				"wxid_novlwrv3lqwv11", //old voice reminder
				"gh_22b87fa7cb3c",//new voice reminder
				"notification_messages"
			];
		
			var fitRunMap = {
		
			};
			/**
			 * 在合适的时间间隔去执行一个函数
			 * 注意：假设函数是频繁调用的，首次立即执行，第二次调用如果小于 interval ,那么会延后到 第二次时间+interval 的时候执行，如果继续这样频繁
			 * 地调用，那么会延后到 limit 所设定的极限值去执行，如果 limit 未设置，那么将会在最后一次事件触发后 +interval 时间去执行
			 * @param handler
			 * @param interval
			 * @param limit
			 */
			var i = 0;
			function fitRun(key,handler,interval,limit){
				var fitRunObj;
				if(fitRunObj = fitRunMap[key]){
					fitRunObj.intervalSum += interval;
					if(limit && limit <= fitRunObj.intervalSum){
						setTimeout(handler,0);
						fitRunMap[key].intervalSum = 0;
					}
		
					clearTimeout(fitRunObj.timer);
					fitRunObj.timer = setTimeout(function(){
						delete fitRunMap[key];
						setTimeout(handler,0);
					},interval)
		
				}else{
					setTimeout(handler,0);
		
					 fitRunMap[key] = {
						intervalSum:0,
						timer:setTimeout(function(){
							delete fitRunMap[key];
						},interval)
					};
		
				}
			}
		
			window.onfocus = function(){window.isFocus = true;};
			window.onblur = function(){window.isFocus = false;};
		
			var service = {
				isLog: false,
				log: function() {
					this.isLog && console.log(arguments);
				},
				now: function() {
					return + new Date();
				},
				getCookie: function(cname) {
					var name = cname + "=";
					var ca = document.cookie.split(';');
					for (var i = 0; i < ca.length; i++) {
						var c = ca[i];
						while (c.charAt(0) == ' ') c = c.substring(1);
						if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
					}
					return "";
				},
				setCookie: function(cname, cvalue, exdays) {
					var d = new Date();
					d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
					var expires = "expires=" + d.toUTCString();
					document.cookie = cname + "=" + cvalue + "; " + expires;
				},
				clearCookie: function () {
					var cookies = document.cookie.split(";");
		
					for (var i = 0; i < cookies.length; i++) {
						var cookie = cookies[i];
						var eqPos = cookie.indexOf("=");
						var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
						document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
					}
				},
				getLocalStorage: function () {
					return window.localStorage || {
							getItem: function(k) { return undefined; },
							setItem: function(k, v) { return; },
							removeItem: function(k) { return; },
							key: function(k) { return ''; }
						};
				},
				htmlEncode: function(str) {
					if (!angular.isString(str)) return '';
					return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
				},
				htmlDecode: function(str) {
					if (!str || str.length == 0) return "";
					return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#39;/g, "\'").replace(/&quot;/g, "\"").replace(/&amp;/g, "&");
				},
				hrefEncode: function(str) {
					var me = this,
						_aLinkArray = str.match(/&lt;a href=(?:'|").*?(?:'|").*?&gt;.*?&lt;\/a&gt;/g);
		
					if (_aLinkArray){
						var _aLink, _sLink;
						for (var i = 0, len = _aLinkArray.length; i < len; ++i) {
							_aLink = /&lt;a href=(?:'|")(.*?)(?:'|").*?&gt;.*?&lt;\/a&gt;/.exec(_aLinkArray[i]);
							if (!_aLink || !_aLink[1]) continue;
							_sLink = _aLink[1];
							if (me.isUrl(_sLink)) {
								str = str.replace(_aLink[0], this.htmlDecode(_aLink[0])).replace(_aLink[1], service.genCheckURL(_aLink[1]));
							}
						}
						return str;
					}else{
						return  str.replace(new RegExp(_urlReg,"ig"), function(){
		
							return '<a target="_blank" href="' + service.genCheckURL(arguments[0].replace(/^(\s|\n)/,'')) + '">' + arguments[0] + '</a>'});
					}
				},
				clearHtmlStr: function(str) {
					return str ? str.replace(/<[^>]*>/g, "") : str;
				},
				clearLinkTag: function(str) {
					return str;
				},
				setCheckUrl: function(accountFactory){
					_checkURLsuffix =
						"&skey=" + encodeURIComponent(accountFactory.getSkey())
						+ "&deviceid=" + encodeURIComponent(accountFactory.getDeviceID())
						+ "&pass_ticket=" + encodeURIComponent(accountFactory.getPassticket())
						+ "&opcode=2&scene=1&username=" + accountFactory.getUserName();
				},
				genCheckURL: function(url){
					if(!_checkURLsuffix) throw "_checkURLsuffix is not ready!";
		
					return confFactory.API_webwxcheckurl +
						"?requrl=" + encodeURIComponent((url.indexOf("http") == 0 ? "" : "http://") + service.clearHtmlStr(service.htmlDecode(url))) + _checkURLsuffix;
				},
				isUrl: function(str) {
					return new RegExp(_urlReg,"i").test(str);
				},
				formatNum: function(_anNum, _anFormatLen) {
					var _sNum = (isNaN(_anNum) ? 0 : _anNum).toString(),
						_nPlusLen = _anFormatLen - _sNum.length;
					return _nPlusLen > 0 ? [ new Array(_nPlusLen + 1).join("0"), _sNum].join("") : _sNum;
				},
				getServerTime: function(argument) {
					return (new Date()).getTime();
				},
				globalEval: function(data) {
					if (data && /\S/.test(data)) { (window.execScript ||
						function(data) {
							window["eval"].call(window, data);
						})(data);
					}
				},
				evalVal: function(_asCode) {
					var _sKey = "a" + this.now(),
					_oValue;
		
					this.globalEval(["(function(){try{window.", _sKey, "=", _asCode, ";}catch(_oError){}})();"].join(""));
					_oValue = window[_sKey];
					window[_sKey] = null;
		
					return _oValue;
				},
				browser: (function(){
					var ua = navigator.userAgent.toLowerCase();
					var matched;
					if( ua.match(/trident/) != null){
						matched =  {
							browser: "msie",
							version:  ua.match(/msie ([\d.]+)/) != null ? ua.match(/msie ([\d.]+)/)[1] : ua.match(/rv:([\d.]+)/)[1]
						};
					}else{
						var match =  /(msie) ([\w.]+)/.exec( ua ) ||
							/(chrome)[ \/]([\w.]+)/.exec( ua ) ||
							/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
							/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
							ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
							[];
						matched = {
							browser: match[ 1 ] || "",
							version: match[ 2 ] || "0"
						};
					}
		
					var browser = {};
		
					if ( matched.browser ) {
						browser[ matched.browser ] = true;
						browser.version = matched.version;
					}
					if ( browser.chrome ) {
						browser.webkit = true;
					} else if ( browser.webkit ) {
						browser.safari = true;
					}
					return browser;
				})(),
				/**
				 * 是否为特殊联系人，
				 * @param  userName
				 */
				isSpUser: function(userName) {
					for (var i = 0,
					len = _SpUsersList.length; i < len; i++) {
						if (_SpUsersList[i] === userName || /@qqim$/.test(userName)) {
							return true;
						}
					}
		
					return false;
				},
				/**
				 * 是否为屏蔽联系人，不显示
				 * @param  userName
				 */
				isShieldUser: function(userName) {
					if (/@lbsroom$/.test(userName) || /@talkroom$/.test(userName)) return true;
		
					for (var i = 0,len = _shieldUsersList.length; i < len; ++i) {
						if (_shieldUsersList[i] == userName) return true;
					}
					return false;
				},
				/**
				 * 是否为群聊
				 * @param  userName
				 */
				isRoomContact: function (userName) {
					if(!userName) return false;
					return /^@@|@chatroom$/.test(userName); // 以@@开头或者@chatroom结尾
				},
				/**
				 * 初始化音频播放器
				 * @param url
				 */
				initMsgNoticePlayer:function (url) {
		
					__webpack_require__.e/* nsure */(2/* duplicate */, function (require) {
						var jplayer = __webpack_require__(278);
						var myPlayer = jQuery('#msgNoticePlayer');
						myPlayer.jPlayer({
							ready: function () {
							},
							swfPath: window.MMSource.jplayerSwfPath,
							solution: 'html, flash',
							supplied: "mp3",
							wmode: "window"
						});
		
						myPlayer.jPlayer("stop");
						myPlayer.jPlayer("setMedia", {mp3: url});
						myPlayer.jPlayer("play");
					});
				},
				/**
				 * 根据UserName获取头像URL
				 * @param userName
				 * @param skey
				 */
				getContactHeadImgUrl: function (options) {
					return (this.isRoomContact(options.UserName) ? confFactory.API_webwxgetheadimg : confFactory.API_webwxgeticon) + '?seq=0&username=' + options.UserName + '&skey=' + options.Skey + (options.MsgId ? ('&msgid=' + options.MsgId) : '') + (options.EncryChatRoomId ? ('&chatroomid=' + options.EncryChatRoomId) : '');
				},
				form: function(url, data) {
					data = data || {};
					var formEl, form = [];
		
					form.push('<form method="POST" action="'+ this.htmlEncode(url) +'">');
					for (var key in data) {
						form.push('<input type="hidden" name="'+key+'" value="'+data[key]+'">');
					}
					form.push('</form>');
					formEl = angular.element(form.join(''))[0];
					document.body.appendChild(formEl);
					formEl.submit();
				},
				queryParser: function(){
					var obj = {};
					var query = location.search.substring(1);
					var vars = query.split('&');
					for(var i = 0, len = vars.length; i < len; i++){
						var pair = vars[i].split('=');
						var key = decodeURIComponent(pair[0]);
						obj[key] = decodeURIComponent(pair[1] || '');
					}
					return obj;
				},
				getSize : function(bytes) {
					bytes = +bytes;
					if(!bytes) return;
					var cRound = 10;
					var BIT_OF_KB = 10, BIT_OF_MB = 20,
						BYTE_OF_KB = 1 << BIT_OF_KB,
						BYTE_OF_MB = 1 << BIT_OF_MB;
		
					// > 1MB
					if ((bytes >> BIT_OF_MB) > 0) {
						var bytesInMB = (Math.round(bytes * cRound / BYTE_OF_MB)) / cRound;
						return "" + bytesInMB + "MB";
					}
		
					// > 0.5K
					if ((bytes >> (BIT_OF_KB - 1)) > 0) {
						var bytesInKB = (Math.round(bytes * cRound / BYTE_OF_KB)) / cRound;
						return "" + bytesInKB + "KB";
					}
		
					return "" + bytes + "B";
				},
				xml2json: function(str){
					if(!str) return {};
					try{
						var index = str.indexOf("<");
						if(index){
							str = str.substr(index);
						}
						return $.xml2json(str);
					}catch(ex){
						console.error(ex);
						return {};
					}
				},
				encodeEmoji:function(str){
					str = str || '';
					str = str.replace(/<span class="(emoji emoji[a-zA-Z0-9]+)"><\/span>/g,'###__EMOJI__$1__###');
					return str;
				},
				decodeEmoji:function(str){
					str = str || '';
					//str = this.htmlEncode(str);
					str = str.replace(/###__EMOJI__(emoji emoji[a-zA-Z0-9]+)__###/g,'<span class="$1"><\/span>');
					return str;
				},
				removeHtmlStrTag:function(str){
					str = str || '';
					str = this.encodeEmoji(str);
					str = this.htmlDecode(str);
					str = this.clearHtmlStr(str);
					str = this.decodeEmoji(str);
					return str;
				},
				safeDigest:function(scope){
					scope =  scope || $rootScope;
					if(!scope.$$phase) {
						scope.$digest();
					}
				},
				wait:function(func,cb,time){
					var time = time || 10;
					setTimeout(function task(){
						if(func()) {
							cb()
						}else{
							setTimeout(task,time);
						}
					},time);
				},
		
				fitRun:fitRun,
				findIndex:function(list,item){
					for(var i = 0; i<list.length;i++){
						if(list[i] == item) return i;
					}
					return -1;
				},
		
		
				// 生成表情的html，统一接口
				genEmoticonHTML: function(className, text){
					return '<img class="' + className + '" ' +
						'text="' + text + (text.indexOf(confFactory.MM_EMOTICON_WEB) > -1 ? "" : confFactory.MM_EMOTICON_WEB) + '" ' +
						'src="' + confFactory.RES_IMG_PLACEHOLDER + '" />';
				},
		
		
				getShareObject:function(key){
					shareObjects[key] =  shareObjects[key] || {};
					return shareObjects[key];
				},
		
		
		
				reportSendState:function(type,value){
					var id= 63637;
					var isIE = this.browser.msie;
					var map = {
						sendFileWrong:{
							ie:63,
							notIe:64
						},
						sendImageWrong:{
							ie:65,
							notIe:66
						},
						uiCheckFail:{
							ie:84,
							notIe:84
						},
						MD5TimeBigFilePerMb:{
							ie:69,
							notIe:70
						},
						MD5TimeSmallFile:{
							ie:71,
							notIe:72
						},
						MD5TimeBigFilePerMbCount:{
							ie:73,
							notIe:74
						},
						MD5TimeSmallFileCount:{
							ie:75,
							notIe:76
						},
						sendcheckElementError:{
							ie:77,
							notIe:77
						},
						sendcheckAttrError:{
							ie:78,
							notIe:78
						},
						chatCurrentNameNotFound:{
							ie:79,
							notIe:79
						},
						navcurrentNameNotFound:{
							ie:80,
							notIe:80
						},
						toUserNameNotFound:{
							ie:81,
							notIe:81
						},
						toUserNameConflictNav:{
							ie:82,
							notIe:82
						},
						toUserNameConflictChat:{
							ie:83,
							notIe:83
						},
						sendFile:{
							ie:86,
							notIe:86
						}
					}
		
		
					var config = map[type];
					if(config){
						this.reportIdkey(id,config[isIE?'ie':'notIe'],value)
					}
		
		
				},
		
		
		
				reportIdkey: function (id, key,value){
					var url = 'https://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportforweb?rid='+id+'&rkey='+key+'&rvalue='+(value||1);
					(new Image()).src = url;
				},
		
		
		
				isUserName: function(){},
				isWindows:  /windows/gi.test(navigator.userAgent),
				isMacOS: /macintosh/gi.test(navigator.userAgent),
				isIPad: /ipad/gi.test(navigator.userAgent)
			};
		
			return service;
		}]);
		})();
	
	/***/ }),
	/* 297 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('emojiFactory', ['$http', '$q','confFactory','utilFactory', function($http, $q, confFactory, utilFactory) {
		
			var service = {
				formatHTMLToSend:function(html){
					var self = this;
					return utilFactory.htmlDecode(utilFactory.clearHtmlStr(
						html
							.replace(/<(?:img|IMG).*?text="(.*?)".*?>/g, function(content, text){ //去img里的text属性替换本身（把img标签(表情)转换成可发送的数据）
								return text.replace(confFactory.MM_EMOTICON_WEB, "");
							})
							.replace(/<(?:br|BR)\/?>/g, "\n")
					)).replace(/<(.*?)>/g, function(str){
						return self.EmojiCodeMap[self.QQFaceMap[str]] || str;
					})
				},
				transformSpanToImg:function(htmlWithSpan){
					var self = this;
					return htmlWithSpan&&htmlWithSpan.replace(/<span.*?class="emoji emoji(.*?)"><\/span>/g,function(){
						var unicode =  self.EmojiCodeMap[arguments[1]];
						return utilFactory.genEmoticonHTML("emoji emoji" +arguments[1],unicode || '')
					});
				},
				emoticonFormat: function (text) {
					var me = this;
					if (text.length == 0) return "";
					text = text
						.replace(new RegExp("(\\[.+?\\])" + "(?!" + confFactory.MM_EMOTICON_WEB + ")", "g"), function (content, text) { // [xxx] QQFace
							return me.getEmoticonByText(text) || content;
						})
						.replace(new RegExp("&lt;(.+?)&gt;" + "(?!" + confFactory.MM_EMOTICON_WEB + ")", "g"), function (content, text) { // <xxx> EmojiFace
							return me.getEmoticonByText("<" + text + ">") || content;
						});
		
					text = me.transformSpanToImg(text)
					return text;
				},
				getEmoticonById:function(id){
					var unicode = this.EmojiCodeMap[id];
					if (!unicode){
						return '';
					}
					return utilFactory.genEmoticonHTML("emoji emoji" + id, unicode);
				},
				getEmoticonByText: function(text){
					var id;
					if(text.indexOf("<") > -1){//emoji格式：<xxx>
						id = this.QQFaceMap[text];
						if (id) return utilFactory.genEmoticonHTML("emoji emoji" + id, this.EmojiCodeMap[id]);
					}else{//QQ表情格式：[xxx]
						id = this.QQFaceMap[text.replace(/\[|\]/g, "")];
						if (id) return utilFactory.genEmoticonHTML("qqemoji qqemoji" + id, text);
					}
		
					//console.error("No such emoji: "+ text);
					return null;
				},
				getTuzkiByMd5: function(md5){
					return this.md52Tuzki[md5];
				},
				getMd5ByTuzki: function(name){
					return this.Tuzki2Md5[name];
				},
				QQFaceList: ["微笑","撇嘴","色","发呆","得意","流泪","害羞","闭嘴","睡","大哭","尴尬","发怒","调皮","呲牙","惊讶","难过","酷","冷汗","抓狂","吐","偷笑","愉快","白眼","傲慢","饥饿","困","惊恐","流汗","憨笑","悠闲","奋斗","咒骂","疑问","嘘","晕","疯了","衰","骷髅","敲打","再见","擦汗","抠鼻","鼓掌","糗大了","坏笑","左哼哼","右哼哼","哈欠","鄙视","委屈","快哭了","阴险","亲亲","吓","可怜","菜刀","西瓜","啤酒","篮球","乒乓","咖啡","饭","猪头","玫瑰","凋谢","嘴唇","爱心","心碎","蛋糕","闪电","炸弹","刀","足球","瓢虫","便便","月亮","太阳","礼物","拥抱","强","弱","握手","胜利","抱拳","勾引","拳头","差劲","爱你","NO","OK","爱情","飞吻","跳跳","发抖","怄火","转圈","磕头","回头","跳绳","投降","激动","乱舞","献吻","左太极","右太极"],
				EmojiList: [ "笑脸","生病","破涕为笑","吐舌","脸红","恐惧","失望","无语",'嘿哈','捂脸','奸笑','机智','皱眉','耶',"鬼魂",'合十',"强壮","庆祝","礼物",'红包','鸡',"开心","大笑","热情","眨眼","色","接吻","亲吻","露齿笑","满意","戏弄","得意","汗","低落","呸","焦虑","担心","震惊","悔恨","眼泪","哭","晕","心烦","生气","睡觉","恶魔","外星人","心","心碎","丘比特","闪烁","星星","叹号","问号","睡着","水滴","音乐","火","便便","弱","拳头","胜利","上","下","右","左","第一","吻","热恋","男孩","女孩","女士","男士","天使","骷髅","红唇","太阳","下雨","多云","雪人","月亮","闪电","海浪","猫","小狗","老鼠","仓鼠","兔子","狗","青蛙","老虎","考拉","熊","猪","牛","野猪","猴子","马","蛇","鸽子","鸡","企鹅","毛虫","章鱼","鱼","鲸鱼","海豚","玫瑰","花","棕榈树","仙人掌","礼盒","南瓜灯","圣诞老人","圣诞树","礼物","铃","气球","CD","相机","录像机","电脑","电视","电话","解锁","锁","钥匙","成交","灯泡","邮箱","浴缸","钱","炸弹","手枪","药丸","橄榄球","篮球","足球","棒球","高尔夫","奖杯","入侵者","唱歌","吉他","比基尼","皇冠","雨伞","手提包","口红","戒指","钻石","咖啡","啤酒","干杯","鸡尾酒","汉堡","薯条","意面","寿司","面条","煎蛋","冰激凌","蛋糕","苹果","飞机","火箭","自行车","高铁","警告","旗","男人","女人","O","X","版权","注册商标","商标"],
				QQFaceMap: {
					"微笑": "0",
					"撇嘴": "1",
					"色": "2",
					"发呆": "3",
					"得意": "4",
					"流泪": "5",
					"害羞": "6",
					"闭嘴": "7",
					"睡": "8",
					"大哭": "9",
					"尴尬": "10",
					"发怒": "11",
					"调皮": "12",
					"呲牙": "13",
					"惊讶": "14",
					"难过": "15",
					"酷": "16",
					"冷汗": "17",
					"抓狂": "18",
					"吐": "19",
					"偷笑": "20",
					"可爱": "21",
					"愉快": "21",
					"白眼": "22",
					"傲慢": "23",
					"饥饿": "24",
					"困": "25",
					"惊恐": "26",
					"流汗": "27",
					"憨笑": "28",
					"悠闲": "29",
					"大兵": "29",
					"奋斗": "30",
					"咒骂": "31",
					"疑问": "32",
					"嘘": "33",
					"晕": "34",
					"疯了": "35",
					"折磨": "35",
					"衰": "36",
					"骷髅": "37",
					"敲打": "38",
					"再见": "39",
					"擦汗": "40",
					"抠鼻": "41",
					"鼓掌": "42",
					"糗大了": "43",
					"坏笑": "44",
					"左哼哼": "45",
					"右哼哼": "46",
					"哈欠": "47",
					"鄙视": "48",
					"委屈": "49",
					"快哭了": "50",
					"阴险": "51",
					"亲亲": "52",
					"吓": "53",
					"可怜": "54",
					"菜刀": "55",
					"西瓜": "56",
					"啤酒": "57",
					"篮球": "58",
					"乒乓": "59",
					"咖啡": "60",
					"饭": "61",
					"猪头": "62",
					"玫瑰": "63",
					"凋谢": "64",
					"嘴唇": "65",
					"示爱": "65",
					"爱心": "66",
					"心碎": "67",
					"蛋糕": "68",
					"闪电": "69",
					"炸弹": "70",
					"刀": "71",
					"足球": "72",
					"瓢虫": "73",
					"便便": "74",
					"月亮": "75",
					"太阳": "76",
					"礼物": "77",
					"拥抱": "78",
					"强": "79",
					"弱": "80",
					"握手": "81",
					"胜利": "82",
					"抱拳": "83",
					"勾引": "84",
					"拳头": "85",
					"差劲": "86",
					"爱你": "87",
					"NO": "88",
					"OK": "89",
					"爱情": "90",
					"飞吻": "91",
					"跳跳": "92",
					"发抖": "93",
					"怄火": "94",
					"转圈": "95",
					"磕头": "96",
					"回头": "97",
					"跳绳": "98",
					"投降": "99",
					"激动": "100",
					"乱舞": "101",
					"献吻": "102",
					"左太极": "103",
					"右太极": "104",
					"嘿哈": "105",
					"捂脸": "106",
					"奸笑": "107",
					"机智": "108",
					"皱眉": "109",
					"耶": "110",
					"鸡": "111",
					"红包": "112",
					"Smile": "0",
					"Grimace": "1",
					"Drool": "2",
					"Scowl": "3",
					"Chill": "4",
					"CoolGuy": "4",
					"Sob": "5",
					"Shy": "6",
					"Shutup": "7",
					"Silent": "7",
					"Sleep": "8",
					"Cry": "9",
					"Awkward": "10",
					"Pout": "11",
					"Angry": "11",
					"Wink": "12",
					"Tongue": "12",
					"Grin": "13",
					"Surprised": "14",
					"Surprise": "14",
					"Frown": "15",
					"Cool": "16",
					"Ruthless": "16",
					"Tension": "17",
					"Blush": "17",
					"Scream": "18",
					"Crazy": "18",
					"Puke": "19",
					"Chuckle": "20",
					"Joyful": "21",
					"Slight": "22",
					"Smug": "23",
					"Hungry": "24",
					"Drowsy": "25",
					"Panic": "26",
					"Sweat": "27",
					"Laugh": "28",
					"Loafer": "29",
					"Commando": "29",
					"Strive": "30",
					"Determined": "30",
					"Scold": "31",
					"Doubt": "32",
					"Shocked": "32",
					"Shhh": "33",
					"Dizzy": "34",
					"Tormented": "35",
					"BadLuck": "36",
					"Toasted": "36",
					"Skull": "37",
					"Hammer": "38",
					"Wave": "39",
					"Relief": "40",
					"Speechless": "40",
					"DigNose": "41",
					"NosePick": "41",
					"Clap": "42",
					"Shame": "43",
					"Trick": "44",
					"Bah！L": "45",
					"Bah！R": "46",
					"Yawn": "47",
					"Lookdown": "48",
					"Pooh-pooh": "48",
					"Wronged": "49",
					"Shrunken": "49",
					"Puling": "50",
					"TearingUp": "50",
					"Sly": "51",
					"Kiss": "52",
					"Uh-oh": "53",
					"Wrath": "53",
					"Whimper": "54",
					"Cleaver": "55",
					"Melon": "56",
					"Watermelon": "56",
					"Beer": "57",
					"Basketball": "58",
					"PingPong": "59",
					"Coffee": "60",
					"Rice": "61",
					"Pig": "62",
					"Rose": "63",
					"Wilt": "64",
					"Lip": "65",
					"Lips": "65",
					"Heart": "66",
					"BrokenHeart": "67",
					"Cake": "68",
					"Lightning": "69",
					"Bomb": "70",
					"Dagger": "71",
					"Soccer": "72",
					"Ladybug": "73",
					"Poop": "74",
					"Moon": "75",
					"Sun": "76",
					"Gift": "77",
					"Hug": "78",
					"Strong": "79",
					"ThumbsUp": "79",
					"Weak": "80",
					"ThumbsDown": "80",
					"Shake": "81",
					"Victory": "82",
					"Peace": "82",
					"Admire": "83",
					"Fight": "83",
					"Beckon": "84",
					"Fist": "85",
					"Pinky": "86",
					"Love": "2",
					"RockOn": "87",
					"No": "88",
					"Nuh-uh": "88",
					"InLove": "90",
					"Blowkiss": "91",
					"Waddle": "92",
					"Tremble": "93",
					"Aaagh!": "94",
					"Twirl": "95",
					"Kotow": "96",
					"Lookback": "97",
					"Dramatic": "97",
					"Jump": "98",
					"JumpRope": "98",
					"Give-in": "99",
					"Surrender": "99",
					"Hooray": "100",
					"HeyHey": "101",
					"Meditate": "101",
					"Smooch": "102",
					"TaiJi L": "103",
					"TaiChi L": "103",
					"TaiJi R": "104",
					"TaiChi R": "104",
					"Hey": "105",
					"Facepalm": "106",
					"Smirk": "107",
					"Smart": "108",
					"Concerned": "109",
					"Yeah!": "110",
					"Chicken": "111",
					"Packet": "112",
					"發呆": "3",
					"流淚": "5",
					"閉嘴": "7",
					"尷尬": "10",
					"發怒": "11",
					"調皮": "12",
					"驚訝": "14",
					"難過": "15",
					"饑餓": "24",
					"累": "25",
					"驚恐": "26",
					"悠閑": "29",
					"奮鬥": "30",
					"咒罵": "31",
					"疑問": "32",
					"噓": "33",
					"暈": "34",
					"瘋了": "35",
					"骷髏頭": "37",
					"再見": "39",
					"摳鼻": "41",
					"羞辱": "43",
					"壞笑": "44",
					"鄙視": "48",
					"陰險": "51",
					"親親": "52",
					"嚇": "53",
					"可憐": "54",
					"籃球": "58",
					"飯": "61",
					"豬頭": "62",
					"枯萎": "64",
					"愛心": "66",
					"閃電": "69",
					"炸彈": "70",
					"甲蟲": "73",
					"太陽": "76",
					"禮物": "77",
					"擁抱": "78",
					"強": "79",
					"勝利": "82",
					"拳頭": "85",
					"差勁": "86",
					"愛你": "88",
					"愛情": "90",
					"飛吻": "91",
					"發抖": "93",
					"噴火": "94",
					"轉圈": "95",
					"磕頭": "96",
					"回頭": "97",
					"跳繩": "98",
					//"投降": "99", // 简体有了
					"激動": "100",
					"亂舞": "101",
					"獻吻": "102",
					"左太極": "103",
					"右太極": "104",
					"吼嘿": "105",
					"掩面": "106",
					// "奸笑": "107", // 和简体一样
					"機智": "108",
					"皺眉": "109",
					"歐耶": "110",
					"雞": "111",
					"紅包": "112",
					"<笑脸>": "1f604",
					"<笑臉>": "1f604",
					"<Laugh>": "1f604",
					"<开心>": "1f60a",
					"<開心>": "1f60a",
					"<Happy>": "1f60a",
					"<大笑>": "1f603",
					"<Big Smile>": "1f603",
					"<热情>": "263a",
					"<熱情>": "263a",
					"<Glowing>": "263a",
					"<眨眼>": "1f609",
					"<Wink>": "1f609",
					"<色>": "1f60d",
					"<Love>": "1f60d",
					"<Drool>": "1f60d",
					"<接吻>": "1f618",
					"<Smooch>": "1f618",
					"<亲吻>": "1f61a",
					"<親吻>": "1f61a",
					"<Kiss>": "1f61a",
					"<脸红>": "1f633",
					"<臉紅>": "1f633",
					"<Blush>": "1f633",
					"<露齿笑>": "1f63c",
					"<露齒笑>": "1f63c",
					"<Grin>": "1f63c",
					"<满意>": "1f60c",
					"<滿意>": "1f60c",
					"<Satisfied>": "1f60c",
					"<戏弄>": "1f61c",
					"<戲弄>": "1f61c",
					"<Tease>": "1f61c",
					"<吐舌>": "1f445",
					"<Tongue>": "1f445",
					"<无语>": "1f612",
					"<無語>": "1f612",
					"<Speechless>": "1f612",
					"<得意>": "1f60f",
					"<Smirk>": "1f60f",
					"<CoolGuy>": "1f60f",
					"<汗>": "1f613",
					"<Sweat>": "1f613",
					"<失望>": "1f640",
					"<Let Down>": "1f640",
					"<合十>": "1f64f",
					"<祈禱>": "1f64f",
					"<低落>": "1f61e",
					"<Low>": "1f61e",
					"<呸>": "1f616",
					"<Ugh>": "1f616",
					"<焦虑>": "1f625",
					"<焦慮>": "1f625",
					"<Anxious>": "1f625",
					"<担心>": "1f630",
					"<擔心>": "1f630",
					"<Worried>": "1f630",
					"<震惊>": "1f628",
					"<震驚>": "1f628",
					"<Shocked>": "1f628",
					"<悔恨>": "1f62b",
					"<D’oh!>": "1f62b",
					"<眼泪>": "1f622",
					"<眼淚>": "1f622",
					"<Tear>": "1f622",
					"<哭>": "1f62d",
					"<Cry>": "1f62d",
					"<破涕为笑>": "1f602",
					"<破涕為笑>": "1f602",
					"<Lol>": "1f602",
					"<晕>": "1f632",
					"<Dead>": "1f632",
					"<Dizzy>": "1f632",
					"<恐惧>": "1f631",
					"<恐懼>": "1f631",
					"<Terror>": "1f631",
					"<心烦>": "1f620",
					"<心煩>": "1f620",
					"<Upset>": "1f620",
					"<生气>": "1f63e",
					"<生氣>": "1f63e",
					"<Angry>": "1f63e",
					"<睡觉>": "1f62a",
					"<睡覺>": "1f62a",
					"<Zzz>": "1f62a",
					"<生病>": "1f637",
					"<Sick>": "1f637",
					"<恶魔>": "1f47f",
					"<惡魔>": "1f47f",
					"<Demon>": "1f47f",
					"<外星人>": "1f47d",
					"<Alien>": "1f47d",
					"<心>": "2764",
					"<Heart>": "2764",
					"<心碎>": "1f494",
					"<Heartbroken>": "1f494",
					"<BrokenHeart>": "1f494",
					"<丘比特>": "1f498",
					"<Cupid>": "1f498",
					"<闪烁>": "2728",
					"<閃爍>": "2728",
					"<Twinkle>": "2728",
					"<星星>": "1f31f",
					"<Star>": "1f31f",
					"<叹号>": "2755",
					"<嘆號>": "2755",
					"<!>": "2755",
					"<问号>": "2754",
					"<問號>": "2754",
					"<?>": "2754",
					"<睡着>": "1f4a4",
					"<睡著>": "1f4a4",
					"<Asleep>": "1f4a4",
					"<水滴>": "1f4a6",
					"<Drops>": "1f4a6",
					"<音乐>": "1f3b5",
					"<音樂>": "1f3b5",
					"<Music>": "1f3b5",
					"<火>": "1f525",
					"<Fire>": "1f525",
					"<便便>": "1f4a9",
					"<Poop>": "1f4a9",
					"<强>": "1f44d",
					"<強>": "1f44d",
					"<ThumbsUp>": "1f44d",
					"<弱>": "1f44e",
					"<ThumbsDown>": "1f44e",
					"<拳头>": "1f44a",
					"<拳頭>": "1f44a",
					"<Punch>": "1f44a",
					"<Fist>": "1f44a",
					"<胜利>": "270c",
					"<勝利>": "270c",
					"<Peace>": "270c",
					"<上>": "1f446",
					"<Up>": "1f446",
					"<下>": "1f447",
					"<Down>": "1f447",
					"<右>": "1f449",
					"<Right>": "1f449",
					"<左>": "1f448",
					"<Left>": "1f448",
					"<第一>": "261d",
					"<#1>": "261d",
					"<强壮>": "1f4aa",
					"<強壯>": "1f4aa",
					"<Strong>": "1f4aa",
					"<吻>": "1f48f",
					"<Kissing>": "1f48f",
					"<热恋>": "1f491",
					"<熱戀>": "1f491",
					"<Couple>": "1f491",
					"<男孩>": "1f466",
					"<Boy>": "1f466",
					"<女孩>": "1f467",
					"<Girl>": "1f467",
					"<女士>": "1f469",
					"<Lady>": "1f469",
					"<男士>": "1f468",
					"<Man>": "1f468",
					"<天使>": "1f47c",
					"<Angel>": "1f47c",
					"<骷髅>": "1f480",
					"<骷髏頭>": "1f480",
					"<骷髏>": "1f480",
					"<Skull>": "1f480",
					"<红唇>": "1f48b",
					"<紅唇>": "1f48b",
					"<Lips>": "1f48b",
					"<太阳>": "2600",
					"<太陽>": "2600",
					"<Sun>": "2600",
					"<下雨>": "2614",
					"<Rain>": "2614",
					"<多云>": "2601",
					"<多雲>": "2601",
					"<Cloud>": "2601",
					"<雪人>": "26c4",
					"<Snowman>": "26c4",
					"<月亮>": "1f319",
					"<Moon>": "1f319",
					"<闪电>": "26a1",
					"<閃電>": "26a1",
					"<Lightning>": "26a1",
					"<海浪>": "1f30a",
					"<Waves>": "1f30a",
					"<猫>": "1f431",
					"<貓>": "1f431",
					"<Cat>": "1f431",
					"<小狗>": "1f429",
					"<Doggy>": "1f429",
					"<老鼠>": "1f42d",
					"<Mouse>": "1f42d",
					"<仓鼠>": "1f439",
					"<倉鼠>": "1f439",
					"<Hamster>": "1f439",
					"<兔子>": "1f430",
					"<Rabbit>": "1f430",
					"<狗>": "1f43a",
					"<Dog>": "1f43a",
					"<青蛙>": "1f438",
					"<Frog>": "1f438",
					"<老虎>": "1f42f",
					"<Tiger>": "1f42f",
					"<考拉>": "1f428",
					"<Koala>": "1f428",
					"<熊>": "1f43b",
					"<Bear>": "1f43b",
					"<猪>": "1f437",
					"<豬>": "1f437",
					"<Pig>": "1f437",
					"<牛>": "1f42e",
					"<Cow>": "1f42e",
					"<野猪>": "1f417",
					"<野豬>": "1f417",
					"<Boar>": "1f417",
					"<猴子>": "1f435",
					"<Monkey>": "1f435",
					"<马>": "1f434",
					"<馬>": "1f434",
					"<Horse>": "1f434",
					"<蛇>": "1f40d",
					"<Snake>": "1f40d",
					"<鸽子>": "1f426",
					"<鴿子>": "1f426",
					"<Pigeon>": "1f426",
					"<鸡>": "1f414",
					"<雞>": "1f414",
					"<Chicken>": "1f414",
					"<企鹅>": "1f427",
					"<企鵝>": "1f427",
					"<Penguin>": "1f427",
					"<毛虫>": "1f41b",
					"<毛蟲>": "1f41b",
					"<Caterpillar>": "1f41b",
					"<章鱼>": "1f419",
					"<八爪魚>": "1f419",
					"<Octopus>": "1f419",
					"<鱼>": "1f420",
					"<魚>": "1f420",
					"<Fish>": "1f420",
					"<鲸鱼>": "1f433",
					"<鯨魚>": "1f433",
					"<Whale>": "1f433",
					"<海豚>": "1f42c",
					"<Dolphin>": "1f42c",
					"<玫瑰>": "1f339",
					"<Rose>": "1f339",
					"<花>": "1f33a",
					"<Flower>": "1f33a",
					"<棕榈树>": "1f334",
					"<棕櫚樹>": "1f334",
					"<Palm>": "1f334",
					"<仙人掌>": "1f335",
					"<Cactus>": "1f335",
					"<礼盒>": "1f49d",
					"<禮盒>": "1f49d",
					"<Candy Box>": "1f49d",
					"<南瓜灯>": "1f383",
					"<南瓜燈>": "1f383",
					"<Jack-o-lantern>": "1f383",
					"<鬼魂>": "1f47b",
					"<Ghost>": "1f47b",
					"<圣诞老人>": "1f385",
					"<聖誕老人>": "1f385",
					"<Santa>": "1f385",
					"<圣诞树>": "1f384",
					"<聖誕樹>": "1f384",
					"<Xmas Tree>": "1f384",
					"<礼物>": "1f381",
					"<禮物>": "1f381",
					"<Gift>": "1f381",
					"<铃>": "1f514",
					"<鈴鐺>": "1f514",
					"<Bell>": "1f514",
					"<庆祝>": "1f389",
					"<慶祝>": "1f389",
					"<Party>": "1f389",
					"<气球>": "1f388",
					"<氣球>": "1f388",
					"<Balloon>": "1f388",
					"<CD>": "1f4bf",
					"<相机>": "1f4f7",
					"<相機>": "1f4f7",
					"<Camera>": "1f4f7",
					"<录像机>": "1f3a5",
					"<錄影機>": "1f3a5",
					"<Film Camera>": "1f3a5",
					"<电脑>": "1f4bb",
					"<電腦>": "1f4bb",
					"<Computer>": "1f4bb",
					"<电视>": "1f4fa",
					"<電視>": "1f4fa",
					"<TV>": "1f4fa",
					"<电话>": "1f4de",
					"<電話>": "1f4de",
					"<Phone>": "1f4de",
					"<解锁>": "1f513",
					"<解鎖>": "1f513",
					"<Unlocked>": "1f513",
					"<锁>": "1f512",
					"<鎖>": "1f512",
					"<Locked>": "1f512",
					"<钥匙>": "1f511",
					"<鑰匙>": "1f511",
					"<Key>": "1f511",
					"<成交>": "1f528",
					"<Judgement>": "1f528",
					"<灯泡>": "1f4a1",
					"<燈泡>": "1f4a1",
					"<Light bulb>": "1f4a1",
					"<邮箱>": "1f4eb",
					"<郵箱>": "1f4eb",
					"<Mail>": "1f4eb",
					"<浴缸>": "1f6c0",
					"<Wash>": "1f6c0",
					"<钱>": "1f4b2",
					"<錢>": "1f4b2",
					"<Money>": "1f4b2",
					"<炸弹>": "1f4a3",
					"<炸彈>": "1f4a3",
					"<Bomb>": "1f4a3",
					"<手枪>": "1f52b",
					"<手槍>": "1f52b",
					"<Pistol>": "1f52b",
					"<药丸>": "1f48a",
					"<藥丸>": "1f48a",
					"<Pill>": "1f48a",
					"<橄榄球>": "1f3c8",
					"<橄欖球>": "1f3c8",
					"<Football>": "1f3c8",
					"<篮球>": "1f3c0",
					"<籃球>": "1f3c0",
					"<Basketball>": "1f3c0",
					"<足球>": "26bd",
					"<Soccer Ball>": "26bd",
					"<Soccer>": "26bd",
					"<棒球>": "26be",
					"<Baseball>": "26be",
					"<高尔夫>": "26f3",
					"<高爾夫>": "26f3",
					"<Golf>": "26f3",
					"<奖杯>": "1f3c6",
					"<獎盃>": "1f3c6",
					"<Trophy>": "1f3c6",
					"<入侵者>": "1f47e",
					"<Invader>": "1f47e",
					"<唱歌>": "1f3a4",
					"<Singing>": "1f3a4",
					"<吉他>": "1f3b8",
					"<Guitar>": "1f3b8",
					"<比基尼>": "1f459",
					"<Bikini>": "1f459",
					"<皇冠>": "1f451",
					"<Crown>": "1f451",
					"<雨伞>": "1f302",
					"<雨傘>": "1f302",
					"<Umbrella>": "1f302",
					"<手提包>": "1f45c",
					"<Purse>": "1f45c",
					"<口红>": "1f484",
					"<口紅>": "1f484",
					"<Lipstick>": "1f484",
					"<戒指>": "1f48d",
					"<Ring>": "1f48d",
					"<钻石>": "1f48e",
					"<鑽石>": "1f48e",
					"<Gem>": "1f48e",
					"<咖啡>": "2615",
					"<Coffee>": "2615",
					"<啤酒>": "1f37a",
					"<Beer>": "1f37a",
					"<干杯>": "1f37b",
					"<乾杯>": "1f37b",
					"<Toast>": "1f37b",
					"<鸡尾酒>": "1f377",
					"<雞尾酒>": "1f377",
					"<Martini>": "1f377",
					"<汉堡>": "1f354",
					"<漢堡>": "1f354",
					"<Burger>": "1f354",
					"<薯条>": "1f35f",
					"<薯條>": "1f35f",
					"<Fries>": "1f35f",
					"<意面>": "1f35d",
					"<意粉>": "1f35d",
					"<Sphaghetti>": "1f35d",
					"<寿司>": "1f363",
					"<壽司>": "1f363",
					"<Sushi>": "1f363",
					"<面条>": "1f35c",
					"<麵條>": "1f35c",
					"<Noodles>": "1f35c",
					"<煎蛋>": "1f373",
					"<Eggs>": "1f373",
					"<冰激凌>": "1f366",
					"<雪糕>": "1f366",
					"<Ice Cream>": "1f366",
					"<蛋糕>": "1f382",
					"<Cake>": "1f382",
					"<苹果>": "1f34f",
					"<蘋果>": "1f34f",
					"<Apple>": "1f34f",
					"<飞机>": "2708",
					"<飛機>": "2708",
					"<Plane>": "2708",
					"<火箭>": "1f680",
					"<Rocket ship>": "1f680",
					"<自行车>": "1f6b2",
					"<單車>": "1f6b2",
					"<Bike>": "1f6b2",
					"<高铁>": "1f684",
					"<高鐵>": "1f684",
					"<Bullet Train>": "1f684",
					"<警告>": "26a0",
					"<Warning>": "26a0",
					"<旗>": "1f3c1",
					"<Flag>": "1f3c1",
					"<男人>": "1f6b9",
					"<男>": "1f6b9",
					"<Men>": "1f6b9",
					"<女人>": "1f6ba",
					"<女>": "1f6ba",
					"<Women>": "1f6ba",
					"<O>": "2b55",
					"<X>": "274e",
					"<版权>": "a9",
					"<版權>": "a9",
					"<Copyright>": "a9",
					"<注册商标>": "ae",
					"<注冊商標>": "ae",
					"<Registered TM>": "ae",
					"<商标>": "2122",
					"<商標>": "2122",
					"<Trademark>": "2122"
				},
				EmojiCodeMap: {
					"1f64f": "\ue41d",
					"1f604" : "\ue415",
					"1f60a" : "\ue056",
					"1f603" : "\ue057",
					"263a" : "\ue414",
					"1f609" : "\ue405",
					"1f60d" : "\ue106",
					"1f618" : "\ue418",
					"1f61a" : "\ue417",
					"1f633" : "\ue40d",
					"1f63c" : "\ue404",
					"1f60c" : "\ue40a",
					"1f61c" : "\ue105",
					"1f445" : "\ue409",
					"1f612" : "\ue40e",
					"1f60f" : "\ue402",
					"1f613" : "\ue108",
					"1f640" : "\ue403",
					"1f61e" : "\ue058",
					"1f616" : "\ue407",
					"1f625" : "\ue401",
					"1f630" : "\ue40f",
					"1f628" : "\ue40b",
					"1f62b" : "\ue406",
					"1f622" : "\ue413",
					"1f62d" : "\ue411",
					"1f602" : "\ue412",
					"1f632" : "\ue410",
					"1f631" : "\ue107",
					"1f620" : "\ue059",
					"1f63e" : "\ue416",
					"1f62a" : "\ue408",
					"1f637" : "\ue40c",
					"1f47f" : "\ue11a",
					"1f47d" : "\ue10c",
					"2764" : "\ue022",
					"1f494" : "\ue023",
					"1f498" : "\ue329",
					"2728" : "\ue32e",
					"1f31f" : "\ue335",
					"2755" : "\ue337",
					"2754" : "\ue336",
					"1f4a4" : "\ue13c",
					"1f4a6" : "\ue331",
					"1f3b5" : "\ue03e",
					"1f525" : "\ue11d",
					"1f4a9" : "\ue05a",
					"1f44d" : "\ue00e",
					"1f44e" : "\ue421",
					"1f44a" : "\ue00d",
					"270c" : "\ue011",
					"1f446" : "\ue22e",
					"1f447" : "\ue22f",
					"1f449" : "\ue231",
					"1f448" : "\ue230",
					"261d" : "\ue00f",
					"1f4aa" : "\ue14c",
					"1f48f" : "\ue111",
					"1f491" : "\ue425",
					"1f466" : "\ue001",
					"1f467" : "\ue002",
					"1f469" : "\ue005",
					"1f468" : "\ue004",
					"1f47c" : "\ue04e",
					"1f480" : "\ue11c",
					"1f48b" : "\ue003",
					"2600" : "\ue04a",
					"2614" : "\ue04b",
					"2601" : "\ue049",
					"26c4" : "\ue048",
					"1f319" : "\ue04c",
					"26a1" : "\ue13d",
					"1f30a" : "\ue43e",
					"1f431" : "\ue04f",
					"1f429" : "\ue052",
					"1f42d" : "\ue053",
					"1f439" : "\ue524",
					"1f430" : "\ue52c",
					"1f43a" : "\ue52a",
					"1f438" : "\ue531",
					"1f42f" : "\ue050",
					"1f428" : "\ue527",
					"1f43b" : "\ue051",
					"1f437" : "\ue10b",
					"1f42e" : "\ue52b",
					"1f417" : "\ue52f",
					"1f435" : "\ue109",
					"1f434" : "\ue01a",
					"1f40d" : "\ue52d",
					"1f426" : "\ue521",
					"1f414" : "\ue52e",
					"1f427" : "\ue055",
					"1f41b" : "\ue525",
					"1f419" : "\ue10a",
					"1f420" : "\ue522",
					"1f433" : "\ue054",
					"1f42c" : "\ue520",
					"1f339" : "\ue032",
					"1f33a" : "\ue303",
					"1f334" : "\ue307",
					"1f335" : "\ue308",
					"1f49d" : "\ue437",
					"1f383" : "\ue445",
					"1f47b" : "\ue11b",
					"1f385" : "\ue448",
					"1f384" : "\ue033",
					"1f381" : "\ue112",
					"1f514" : "\ue325",
					"1f389" : "\ue312",
					"1f388" : "\ue310",
					"1f4bf" : "\ue126",
					"1f4f7" : "\ue008",
					"1f3a5" : "\ue03d",
					"1f4bb" : "\ue00c",
					"1f4fa" : "\ue12a",
					"1f4de" : "\ue009",
					"1f513" : "\ue145",
					"1f512" : "\ue144",
					"1f511" : "\ue03f",
					"1f528" : "\ue116",
					"1f4a1" : "\ue10f",
					"1f4eb" : "\ue101",
					"1f6c0" : "\ue13f",
					"1f4b2" : "\ue12f",
					"1f4a3" : "\ue311",
					"1f52b" : "\ue113",
					"1f48a" : "\ue30f",
					"1f3c8" : "\ue42b",
					"1f3c0" : "\ue42a",
					"26bd" : "\ue018",
					"26be" : "\ue016",
					"26f3" : "\ue014",
					"1f3c6" : "\ue131",
					"1f47e" : "\ue12b",
					"1f3a4" : "\ue03c",
					"1f3b8" : "\ue041",
					"1f459" : "\ue322",
					"1f451" : "\ue10e",
					"1f302" : "\ue43c",
					"1f45c" : "\ue323",
					"1f484" : "\ue31c",
					"1f48d" : "\ue034",
					"1f48e" : "\ue035",
					"2615" : "\ue045",
					"1f37a" : "\ue047",
					"1f37b" : "\ue30c",
					"1f377" : "\ue044",
					"1f354" : "\ue120",
					"1f35f" : "\ue33b",
					"1f35d" : "\ue33f",
					"1f363" : "\ue344",
					"1f35c" : "\ue340",
					"1f373" : "\ue147",
					"1f366" : "\ue33a",
					"1f382" : "\ue34b",
					"1f34f" : "\ue345",
					"2708" : "\ue01d",
					"1f680" : "\ue10d",
					"1f6b2" : "\ue136",
					"1f684" : "\ue435",
					"26a0" : "\ue252",
					"1f3c1" : "\ue132",
					"1f6b9" : "\ue138",
					"1f6ba" : "\ue139",
					"2b55" : "\ue332",
					"274e" : "\ue333",
					"a9" : "\ue24e",
					"ae" : "\ue24f",
					"2122" : "\ue537"
				},
				EmojiCodeConv: {
					"[Silent]" : "[Shutup]",
					"[Angry]" : "[Pout]",
					"[Tongue]" : "[Wink]",
					"[Surprise]" : "[Surprised]",
					"[Ruthless]" : "[Cool]",
					"[Blush]" : "[Tension]",
					"[Crazy]" : "[Scream]",
					"[Commando]" : "[Loafer]",
					"[Determined]" : "[Strive]",
					"[Shocked]" : "[Doubt]",
					"[Tormented]" : "[Crazy]",
					"[Toasted]" : "[BadLuck]",
					"[Speechless]" : "[Relief]",
					"[NosePick]" : "[DigNose]",
					"[Pooh-pooh]" : "[Lookdown]",
					"[Shrunken]" : "[Wronged]",
					"[TearingUp]" : "[Puling]",
					"[Wrath]" : "[Uh-oh]",
					"[Watermelon]" : "[Melon]",
					"[ThumbsUp]" : "[Strong]",
					"[ThumbsDown]" : "[Weak]",
					"[Peace]" : "[Victory]",
					"[Fight]" : "[Admire]",
					"[RockOn]" : "[Love]",
					"[Nuh-uh]" : "[No]",
					"[Dramatic]" : "[Lookback]",
					"[JumpRope]" : "[Jump]",
					"[Surrender]" : "[Give-in]",
					"[Meditate]" : "[HeyHey]",
					"[TaiChi L]" : "[TaiJi L]",
					"[TaiChi R]" : "[TaiJi R]"
				},
		
				Tuzki2Md5: {
					"icon_001.gif" : "44682e637b75a3f5d6747d61dbd23a15",
					"icon_002.gif" : "846f30447c5c4c9beefeb5a61bec0ba3",
					"icon_006.gif" : "86cb157e9c44b2c9934e4e430790776d",
					"icon_007.gif" : "5883b606506766a8733afde516166dad",
					"icon_009.gif" : "ea675fef6e28b0244c4577c6d5a2e5c9",
					"icon_010.gif" : "b25b5a719caeaca7525dd9d0ef0be4bb",
					"icon_012.gif" : "8690f2ec5676b9d2d70f7cba012e772e",
					"icon_013.gif" : "5ce1249c690762727b97efa75b685e2b",
					"icon_018.gif" : "b51826394461eb67e2ecbdd8900a25d9",
					"icon_019.gif" : "a13aac17bb8c649dc7797dd5ad0bf97f",
					"icon_020.gif" : "9cf03d450b27e8011bba02a652bc357a",
					"icon_021.gif" : "5462d752e528d1635816e38469ce4151",
					"icon_022.gif" : "ed18d9a312413ea32838bb4d7bb8317c",
					"icon_024.gif" : "3cdca9051658348b5a11ba14dc6a3aca",
					"icon_027.gif" : "0e1dcfa77dbbdfe984edd644cfb5da79",
					"icon_028.gif" : "3a4dc10bc33c74726f46ba1eacd97391",
					"icon_029.gif" : "7590a6e186522063b994eaf8f45673bf",
					"icon_030.gif" : "1280edfca8cb1dcf78e44789358e35d6",
					"icon_033.gif" : "2c4597ce27b24af08652be6bea644c32",
					"icon_035.gif" : "c6345f716d706b8b9df53b0b6fff82cd",
					"icon_040.gif" : "ca17f472025f0943917b443faeaee999"
				},
				md52Tuzki: {
					"44682e637b75a3f5d6747d61dbd23a15" : "icon_001.gif",
					"846f30447c5c4c9beefeb5a61bec0ba3" : "icon_002.gif",
					"86cb157e9c44b2c9934e4e430790776d" : "icon_006.gif",
					"5883b606506766a8733afde516166dad" : "icon_007.gif",
					"ea675fef6e28b0244c4577c6d5a2e5c9" : "icon_009.gif",
					"b25b5a719caeaca7525dd9d0ef0be4bb" : "icon_010.gif",
					"8690f2ec5676b9d2d70f7cba012e772e" : "icon_012.gif",
					"5ce1249c690762727b97efa75b685e2b" : "icon_013.gif",
					"b51826394461eb67e2ecbdd8900a25d9" : "icon_018.gif",
					"a13aac17bb8c649dc7797dd5ad0bf97f" : "icon_019.gif",
					"9cf03d450b27e8011bba02a652bc357a" : "icon_020.gif",
					"5462d752e528d1635816e38469ce4151" : "icon_021.gif",
					"ed18d9a312413ea32838bb4d7bb8317c" : "icon_022.gif",
					"3cdca9051658348b5a11ba14dc6a3aca" : "icon_024.gif",
					"0e1dcfa77dbbdfe984edd644cfb5da79" : "icon_027.gif",
					"3a4dc10bc33c74726f46ba1eacd97391" : "icon_028.gif",
					"7590a6e186522063b994eaf8f45673bf" : "icon_029.gif",
					"1280edfca8cb1dcf78e44789358e35d6" : "icon_030.gif",
					"2c4597ce27b24af08652be6bea644c32" : "icon_033.gif",
					"c6345f716d706b8b9df53b0b6fff82cd" : "icon_035.gif",
					"ca17f472025f0943917b443faeaee999" : "icon_040.gif"
				}
			};
			service.TuzkiList = (function(){
				var names = [], Tuzkis = service.Tuzki2Md5;
				for(var name in Tuzkis){
					names.push(name);
				}
				return names;
			})();
			return service;
		}]);
		})();
	
	/***/ }),
	/* 298 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('contextMenuFactory',['$timeout','confFactory',function($timeout,confFactory) {
			var _timeStamp = "",
				_contextMenuEvent;
		
			var service = {
				getContextMenuEventTimeStamp: function (argument) {
					return _timeStamp;
				},
				setContextMenuEvent: function (e) {
					_contextMenuEvent = e;
					_timeStamp = e.timeStamp;
				},
				getContextMenuEvent: function (argument) {
					return _contextMenuEvent;
				}
			};
			return service;
		}]);
		
		})();
	
	/***/ }),
	/* 299 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('screenShotFactory', ['confFactory', 'reportService',function(confFactory,reportService) {
			var _CAPTURE_PLUGIN_ID = "screencapture",
				_UPLOADER_PLUGIN_ID = "uploader";
			// 新版截图插件地址
			var _capturePlugin = null, uploader = null;
			function _getCapturePlugin() {
				return _capturePlugin || (_capturePlugin = QMActivex.create(_CAPTURE_PLUGIN_ID));
			}
			function _getUploader() {
				return uploader || (uploader = QMActivex.create(_UPLOADER_PLUGIN_ID));
			}
			function _isClipBoardImage() {
				return _getCapturePlugin() && _getCapturePlugin().IsClipBoardImage;
			}
			function _saveImg() {
				if (!_getCapturePlugin() || !_isClipBoardImage()) return false;
		
				return _getCapturePlugin().SaveClipBoardBmpToFile(1);
			}
			function _uploadClipBoardImg(data, callback) {
				var _uploader = _getUploader();
				_uploader.StopUpload();
				_uploader.ClearHeaders();
				_uploader.ClearFormItems();
		
				if (_uploader) {
					_uploader.URL = (MMDEV ? 'http://wx.qq.com' : "http://" + location.hostname) + confFactory.API_webwxpreview + "?fun=upload";
					_uploader.AddHeader("Cookie", document.cookie);
					_uploader.AddFormItem("msgimgrequest", 0, 0, data);
					_uploader.AddFormItem("filename", 1, 4, _saveImg());
		
					_uploader.OnEvent = function(obj, event) {
						switch( event ){
							case 2:
								break;
							case 3:
								if (_uploader) {
									callback(JSON.parse(_uploader.Response));
									_uploader = null;
								}
								break;
							case 1: // error
								console.error("screensnap upload error");
								reportService.report(reportService.ReportType.uploaderError,{
									text:'screensnap upload error',
									url:_uploader.URL
								})
								callback({});
								_uploader = null;
								break;
						}
					};
					_uploader.StartUpload();
				}
			}
			return{
				isSupport : function() {
					return window.QMActivex && QMActivex.isSupport(_CAPTURE_PLUGIN_ID) > 0;
				},
		
				install : function(){
					window.open(QMActivex.installUrl.replace(/^https/, "http"));
				},
		
				capture : function(_aoCallbacks) {
					var _oScreenCaptureInsatnce = _getCapturePlugin();
					if (_oScreenCaptureInsatnce) {
						_oScreenCaptureInsatnce.OnCaptureFinished = _aoCallbacks.ok;
					}
					_oScreenCaptureInsatnce.OnCaptureCanceled = function(){};
					_oScreenCaptureInsatnce.DoCapture();
				},
		
				isClipBoardImage : function() {
					return _isClipBoardImage();
				},
		
				upload : function(data, callback) {
					if (_isClipBoardImage()) {
						_uploadClipBoardImg(data, callback);
						return true;
					}
				}
			};
		}]);
		})();
	
	/***/ }),
	/* 300 */
	/***/ (function(module, exports) {
	
		/**
		 * Created by jfengjiang on 2015/1/4.
		 */
		
		(function(){
			'use strict';
		
			/**
			 * 桌面通知
			 * 说明：Chrome、Safari和安装了html5notifications插件的，都支持window.webkitNotification；
			 *      Chrome 23起不需要webkit私有前缀，但是如果使用无私有前缀的对象请求权限时，会阻塞浏览器，因此请求权限时还是使用私有前缀的方法，其他情况使用无前缀对象
			 *      firefox mobile使用navigator.mozNotification
			 *      IE9+使用window.external && window.external.msIsSiteMode()
			 *
			 */
		
			angular.module('Services')
				.factory('notificationFactory', ['utilFactory', function(utilFactory){
		
		
					/*
					 Safari native methods required for Notifications do NOT run in strict mode.
					 */
					//"use strict";
					var PERMISSION_DEFAULT = "default",
						PERMISSION_GRANTED = "granted",
						PERMISSION_DENIED = "denied",
						PERMISSION = [PERMISSION_GRANTED, PERMISSION_DEFAULT, PERMISSION_DENIED],
						defaultSetting = {
							pageVisibility: false,
							autoClose: 5000,
							total: 3
						},
						emptyString = "",
						isSupported = (function () {
							var isSupported = false;
							/*
							 * Use try {} catch() {} because the check for IE may throws an exception
							 * if the code is run on browser that is not Safar/Chrome/IE or
							 * Firefox with html5notifications plugin.
							 *
							 * Also, we canNOT detect if msIsSiteMode method exists, as it is
							 * a method of host object. In IE check for existing method of host
							 * object returns undefined. So, we try to run it - if it runs
							 * successfully - then it is IE9+, if not - an exceptions is thrown.
							 */
							try {
								isSupported = !!(/* Safari, Chrome */window.Notification || /* Chrome & ff-html5notifications plugin */window.webkitNotifications || /* Firefox Mobile */navigator.mozNotification || /* IE9+ */(window.external && window.external.msIsSiteMode() !== undefined));
							} catch (e) {
								utilFactory.log('Services.notificationFactory.isSupport error: ', e);
							}
							return isSupported;
						}()),
						ieVerification = Math.floor((Math.random() * 10) + 1),
						notifications = [],
						settings = defaultSetting;
					function getNotification(title, options) {
						var notification;
						if (window.Notification) { /* Safari 6, Chrome (23+) */
							notification =  new window.Notification(title, {
								/* The notification's icon - For Chrome in Windows, Linux & Chrome OS */
								icon: angular.isString(options.icon) ? options.icon : options.icon.x32,
								/* The notification’s subtitle. */
								body: options.body || emptyString,
								/*
								 The notification’s unique identifier.
								 This prevents duplicate entries from appearing if the user has multiple instances of your website open at once.
								 */
								tag: options.tag || emptyString
							});
						} else if (window.webkitNotifications) { /* FF with html5Notifications plugin installed */
							notification = window.webkitNotifications.createNotification(options.icon, title, options.body);
							notification.show();
						} else if (navigator.mozNotification) { /* Firefox Mobile */
							notification = navigator.mozNotification.createNotification(title, options.body, options.icon);
							notification.show();
						} else if (window.external && window.external.msIsSiteMode()) { /* IE9+ */
							//Clear any previous notifications
							window.external.msSiteModeClearIconOverlay();
							window.external.msSiteModeSetIconOverlay((angular.isString(options.icon) ? options.icon : options.icon.x16), title);
							window.external.msSiteModeActivate();
							notification = {
								"ieVerification": ieVerification + 1
							};
						}
						return notification;
					}
					function getWrapper(notification) {
						return {
							close: function () {
								if (notification) {
									if (notification.close) {
										//http://code.google.com/p/ff-html5notifications/issues/detail?id=58
										notification.close();
									}
									else if (notification.cancel) {
										notification.cancel();
									} else if (window.external && window.external.msIsSiteMode()) {
										if (notification.ieVerification === ieVerification) {
											window.external.msSiteModeClearIconOverlay();
										}
									}
								}
							}
						};
					}
					function requestPermission(callback) {
						if (!isSupported) { return; }
						var callbackFunction = angular.isFunction(callback) ? callback : angular.noop;
						if (window.webkitNotifications && window.webkitNotifications.checkPermission) {
							window.webkitNotifications.requestPermission(callbackFunction);
						} else if (window.Notification && window.Notification.requestPermission) {
							window.Notification.requestPermission(callbackFunction);
						}
					}
					function permissionLevel() {
						var permission;
						if (!isSupported) { return; }
						if (window.Notification && window.Notification.permissionLevel) {
							//Safari 6
							permission = window.Notification.permissionLevel();
						} else if (window.webkitNotifications && window.webkitNotifications.checkPermission) {
							//Chrome & Firefox with html5-notifications plugin installed
							permission = PERMISSION[window.webkitNotifications.checkPermission()];
						} else if (window.Notification && window.Notification.permission) {
							// Firefox 23+
							permission = window.Notification.permission;
						} else if (navigator.mozNotification) {
							//Firefox Mobile
							permission = PERMISSION_GRANTED;
						} else if (window.external && (window.external.msIsSiteMode() !== undefined)) { /* keep last */
							//IE9+
							permission = window.external.msIsSiteMode() ? PERMISSION_GRANTED : PERMISSION_DEFAULT;
						}
						return permission;
					}
					/**
					 *
					 */
					function config(params) {
						if (params && angular.isObject(params)) {
							angular.extend(settings, params);
						}
						return settings;
					}
					function isDocumentHidden() {
						return settings.pageVisibility ? (document.hidden || document.msHidden || document.mozHidden || document.webkitHidden) : true;
					}
					function createNotification(title, options) {
						if (notifications.length >= settings.total){
							notifications.shift().close();
						}
		
						var notification,
							notificationWrapper;
						/*
						 Return undefined if notifications are not supported.
		
						 Return undefined if no permissions for displaying notifications.
		
						 Title and icons are required. Return undefined if not set.
						 */
						if (isSupported && isDocumentHidden() && angular.isString(title) && (options && (angular.isString(options.icon) || angular.isObject(options.icon))) && (permissionLevel() === PERMISSION_GRANTED)) {
							notification = getNotification(title, options);
						}
						notificationWrapper = getWrapper(notification);
						notifications.push(notificationWrapper);
						//Auto-close notification
						if (settings.autoClose && notification && !notification.ieVerification && notification.addEventListener) {
							notification.addEventListener("show", function () {
								var notification = notificationWrapper;
								setTimeout(function () {
									notification.close();
								}, settings.autoClose);
							});
						}
						return notification;
					}
		
					var service = {
						PERMISSION_DEFAULT: PERMISSION_DEFAULT,
						PERMISSION_GRANTED: PERMISSION_GRANTED,
						PERMISSION_DENIED: PERMISSION_DENIED,
						isSupported: isSupported,
						config: config,
						createNotification: createNotification,
						permissionLevel: permissionLevel,
						requestPermission: requestPermission
					};
		
					if (angular.isFunction(Object.seal)) {
						Object.seal(service);
					}
					
					
					return service;
				}]);
		})();
	
	/***/ }),
	/* 301 */
	/***/ (function(module, exports) {
	
		(function(_aoUndefined){
			'use strict';
		
			/* Services */
		
			angular.module('Services')
				.factory('resourceService', [
					'$timeout',
					'$http',
					'$q',
					'$window',
					function($timeout,$http, $q,$window) {
						var pageLoaded = false;
		
						$($window).on('load',function(){
							pageLoaded = true;
							run();
						})
						var loadInterval=4;
						var parallelLimit = 6;
						var runningTask = 0;
						var priorityTaskList = [];
						var taskList = [];
						var j = 0;
						var errorNum = 0;
						var pendingNum = 0;
						var pendingLimit = 5000;
		
						var loadMap = {
							image:function(task,cb){
								var image = new Image();
								image.src=task.url;
								j++;
								//console.log('loadimg',j);
								var startTime = Date.now();
								image.onload = function(){
									if((Date.now() - startTime) > pendingLimit){
										pendingNum++;
									}
									cb(task);
								}
		
								image.onerror = function(){
									errorNum++;
								}
							},
							video:function(task,cb){
		
							}
						};
						var callBackList = [];
		
						/**
						 *
						 * @param opt.priority 是否优先
						 * @param opt.combo 结果是否 combo
						 */
						function load(list,opt,cb){
							if(!(list instanceof Array)){
								list = [list];
							}
		
							if(!(list.length > 0)){
								// 没有任务便返回
								$timeout(cb,0);
								return;
							}
							opt = opt || {};
		
		
							var theTaskList = opt.priority?priorityTaskList:taskList;
							var cbKey = callBackList.push({
								callback:cb || function(){},
								taskNum:list.length,
								combo:opt.combo,
								result:{}
							}) - 1;
							var task;
		
		
							for(var i = 0;i<list.length;i++){
								task = list[i];
								task._cbKey = cbKey;
								// 如果没有设置key ，则默认是 url， 而如果只有一个任务，cb 便直接返回结果
								task._resultKey = task.key || task.url;
								theTaskList.push(task);
							}
							run();
						}
		
						var i = 0;
		
						function resultCollect(task,result){
							var cbObj = callBackList[task._cbKey];
							if(cbObj.combo){
								cbObj.result[task._resultKey] = result;
								cbObj.taskNum--;
								if(cbObj.taskNum == 0){
									cbObj.callback(cbObj.result);
								}
							}else{
								i++;
								//console.log('load',i)
								cbObj.callback(result);
								cbObj.taskNum-- ;
							}
		
		
							if(cbObj.taskNum == 0){
								//console.log('load',i)
								callBackList[task._cbKey] = undefined;
							}
		
							runningTask -- ;
		
							run();
						}
		
		
						function run(){
							/*if(!pageLoaded) return;
		
							var task ;
		
							while(runningTask < parallelLimit && (task = priorityTaskList.shift() || ( pageLoaded && taskList.shift()))){
								runningTask ++;
								setTimeout((function(task){
									return function(){loadMap[task.type](task,resultCollect)};
								})(task),loadInterval);
							}*/
						}
		
		
						var service ={
							 load:load
						};
		
						return service;
					}]);
		})();
	
	
	/***/ }),
	/* 302 */
	/***/ (function(module, exports) {
	
		/**
		 * Created by arminchen on 2015/2/6.
		 */
		(function() {
			'use strict';
		
			/* Services */
			angular.module('Services').factory('stateManageService', ['$http', '$q',
				function($http, $q) {
		
					var stateMap={
						'sender:hasText':false,
						'sender:active':false,
						'navChat:active':false,
						'navContact:active':false,
						'contactPicker:active':false,
						'dialog:open':false
					}
		
					var listenMap = {}
		
					var actionMap = {
						'navChat:active':{
							'navContact:active':false,
							'navRead:active':false
						},
						'navRead:active':{
							'navChat:active':false,
							'navContact:active':false
						},
						'navContact:active':{
							'navChat:active':false,
							'navRead:active':false
						}
					}
					var canDoMap ={
						navKeydown:function(){
							return ((!stateMap['sender:hasText'] /*&& stateMap['sender:active']*/)/*||!stateMap['sender:active']*/)&&!stateMap['contactPicker:active'];
						},
						pasteFile:function(){
							return !stateMap['dialog:open']
						}
					}
		
					var dataMap={};
		
					function handler(actionObj){
						if(typeof  actionObj === 'object'){
							for(var state in actionObj){
								if(stateMap[state]!==actionObj[state]){
									trigger(state,actionObj[state]);
								}
								stateMap[state] = actionObj[state];
		
							}
						}
					}
		
					function trigger(state,value){
						var listeners = listenMap[state];
						if(listeners){
							for(var i =0;i<listeners.length;i++){
								listeners[i](value);
							}
						}
					}
		
		
		
		
					var service = {
						change:function(state,value){
							var stateActions = actionMap[state];
							var actionStr = value.toString();
							var actionObj;
							if(stateActions){
								if(stateActions['false'] || stateActions['true']){
									actionObj =  stateActions[actionStr];
								}else{
									actionObj = actionStr=='true'?stateActions:undefined;
								}
							}
							if(stateMap[state]!==value){
								trigger(state,value);
							}
							stateMap[state]=value;
							handler(actionObj);
						},
						canDo:function(event){
							return canDoMap[event]();
						},
		
						on:function(state,cb){
							if(!listenMap[state]){
								listenMap[state] = [];
							}
		
							var value = stateMap[state];
							if(typeof value !== 'undefined'){
							   trigger(state,value);
							}
		
							listenMap[state].push(cb);
						},
						off:function(state,cb){
							var listens = listenMap[state];
							var listen;
							if(!listens) return;
		
							for(var i = 0;i<listens.length;i++){
								listen = listens[i];
								if(listen == cb){
									listens.splice(i,1);
									return ;
								}
							}
						},
						data:function(key,value){
							if(arguments.length === 2){
								dataMap[key]=value;
							}
		
							return dataMap[key]
						}
					}
					return service;
				}]);
		
		})();
	
	/***/ }),
	/* 303 */
	/***/ (function(module, exports) {
	
		(function () {
			'use strict';
			angular.module('Services')
				.factory('oplogFactory', ['$http', 'accountFactory', 'confFactory',
					function ($http, accountFactory, confFactory) {
						return {
							feedback: function (ctn) {
								$http({
									method: "POST",
									url: confFactory.API_webwxfeedback,
									data: angular.extend(accountFactory.getBaseRequest(), {
										MachineType: "webwx",
										Content: ctn,
										ReportType: 0 //default
									})
								});
							}
						};
					}]);
		})();
	
	
	/***/ }),
	/* 304 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Services')
		.factory('reportService', ['$http','$rootScope','confFactory','accountFactory',function($http,$rootScope,confFactory ,accountFactory) {
			var DELAY = 3000;
			var reportList = [];
			var storageList=[];
			var runTimeReportMap = {};
			var timer ;
			var REPORT_KEY = 'reportService';
			var storage = getLocalStorage();
			var ReportType ={
				// 带有 -error 字样的错误类型总是第一时间被上报
				jsError:'[js-error]',
				initError:'[init-error]',
				logicError:'[logic-error]',
				uploaderError:'[uploader-error]',
				netError:'[net-error]',
				imageLoadError:'[image-load-error]',
				picError:'[pic-error]',
				cookieError:'[cookie-error]',
		
				sendError:'[send-error]',
		
				timing:'[app-timing]',
				runtime:'[app-runtime]',
				contactReady:'[contact-ready-time]',
				initReady:'[init-ready-time]',
		
				actionRecord:'[action-record]',
		
				WinAdPV: '[win-ad-pv]', // Windows平台广告曝光量
				click2CloseAd: '[click-to-close-ad]', // 骚扰，直接叉掉的量
				clickAndCloseAd: '[click-and-close-ad]', // 好奇点一下的量
		
				sessionData: '[session-data]'
			};
		
			var reportHanglerMap = {};
		
			reportHanglerMap[ReportType.jsError] = handleJsError;
			//reportHanglerMap[ReportType.timing] = handleTiming;
		
			drainStorageReport();
			reportAppRunTime();
		
			var appTimingObj = {};
			var isTimingSended = false;
		
			function getTiming (){
				var pageTiming,result = {};
				result.appTiming = appTimingObj;
				if(window.performance && (pageTiming = window.performance.timing)){
					result.pageTiming = pageTiming;
				}
				return result;
			}
			function handleTiming (data){
		
		
				if(data.needSend){
		
					_report({
						Type:1,
						Text: JSON.stringify({type:ReportType.timing,data:getTiming()})
					},true);
					isTimingSended = true;
					startRunTimeReport();
				} else if(data.fullTiming){
					_report({
						Type:1,
						Text: JSON.stringify({type:ReportType.timing,data:data.fullTiming})
					},true)
		
				}else{
					$.extend(appTimingObj,data.timing);
				}
		
		
		
		
		
		
			}
			function handleJsError(err){
				return {
					message:err.message,
					stack:err.stack && err.stack.replace(/\n/g,'\\n'),
					other:err.other
				};
			}
		
			function format(tpl,data){
				return tpl;
			}
		
			function handlerReportData(type,data){
				var hander = reportHanglerMap[type];
				var result = data;
				if(typeof hander == 'function'){
					result = hander(data);
				} else if(typeof hander == 'string'){
					result = format(hander,data);
				}
		
				var resultText = JSON.stringify({
					type:type,
					data:result
				});
		
		
				return resultText;
			}
		
		
			function drainStorageReport(){
				var storageList = JSON.parse(storage.getItem(REPORT_KEY));
				if(storageList && storageList.length > 0){
					for(var i = 0; i < storageList.length;i++){
						report(storageList[i].type,storageList[i].data);
					}
					storage.setItem(REPORT_KEY,null);
				}
		
			}
		
		
			function report(type,data,isImmediately){
				if(typeof type == undefined){
					console.error('【report】','report type 不存在：',type,data);
					return ;
				}
		
		
				if(type == ReportType.timing){
					handleTiming(data);
					return;
				}
		
		
				var immediately = isImmediately || false;
				var reportData;
				if(type.indexOf('send-error')>0){
					immediately = true;
					reportData = {
						Type:16,
						Text: handlerReportData(type,data)
					};
				}else{
					if(type.indexOf('-error') > 0){
						immediately = true;
						reportData = {
							Type:2,
							Text: handlerReportData(type,data)
						};
					}else{
						reportData = {
							Type:1,
							Text: handlerReportData(type,data)
						};
					}
		
					_report(reportData,immediately);
				}
		
			}
		
		
			function startRunTimeReport(){
				// todo:累积数据，页面unload的时候一次性发送统计数据
				var timeList = [0,15000,600000];
		
				for(var i = 0;i<timeList.length;i++){
					 setTimeout((function(time){
						 return function(){
							runTimeReportMap[time] = analyze($rootScope);
					 }})(timeList[i]),timeList[i])
				}
			}
			function reportAppRunTime(){
		
				$( window ).unload(function() {
					runTimeReportMap['unload'] = analyze($rootScope);
					storageList.push({
						type:ReportType.runtime,
						data:runTimeReportMap
					})
		
		
					!isTimingSended&&storageList.push({
						type:ReportType.timing,
						data:{
							fullTiming:getTiming()
						}
					})
		
					localStorage.setItem(REPORT_KEY,JSON.stringify(storageList))
				});
		
		
				// todo: 运行时状态手机
		
		
			}
		
			function getLocalStorage(){
				var result;
				var nativeStorage = window.localStorage;
		
				if(nativeStorage){
					result = {
						setItem:function(){
							try{
								nativeStorage.setItem.apply(nativeStorage,arguments)
							}catch (e){console.log('localStory 不能使用')}
						},
						getItem:function(){
							try{
								return  nativeStorage.getItem.apply(nativeStorage,arguments)
							}catch (e){console.log('localStory 不能使用')}
						}
					}
				}else{
					result =  {
						setItem:function(){},
						getItem:function(){}
					}
				}
		
				return result;
			}
		
			function analyze(scope,result){
				if(!result) result = {
					listenerCount:0,
					watchersCount:0,
					scopesCount:0
				}
				var currentChild = scope.$$childHead;
		
				while(currentChild){
					analyze(currentChild,result);
					currentChild = currentChild.$$nextSibling;
				}
		
				var listenerCount = scope.$$listenerCount;
				for(var listenerKey in listenerCount){
					result.listenerCount += listenerCount[listenerKey];
				}
		
				result.watchersCount += scope.$$watchers && scope.$$watchers.length;
				result.scopesCount += 1;
		
				return result;
				}
		
			function _report(data,immediately){
				reportList.push(data);
				if(immediately){
					send()
				}else{
					timer && clearTimeout(timer);
					timer = setTimeout(function(){
						send()
					},DELAY)
				}
			}
		
			function send(){
				var list = reportList.splice(0);
				post(list);
			}
		
			window._errorHandler = function(err){
				report(ReportType.jsError,err)
			}
		
			function post(list){
				$http({
					method: "POST",
					url: confFactory.API_webwxreport+'?fun=new',
					data:{
						BaseRequest:{
							Uin:accountFactory.getUin(),
							Sid:accountFactory.getSid(),
							DeviceID: accountFactory.getDeviceID()
						},
						Count:list.length,
						List:list
					}
				}).success(function (data) {
					// do nothing
					console.log(data);
					console.timeEnd('report');
				}).error(function (data) {
					// do nothing
					console.log(data);
					console.timeEnd('report');
				});
		
			}
		
			var service = {
				report:report,
				ReportType:ReportType
			};
			return service;
		}]);
		})();
	
	/***/ }),
	/* 305 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function(){
			'use strict';
			
			/* Services */
			
			angular.module('Services')
			.factory('monitorService', ['$http','$rootScope','confFactory','accountFactory',function($http,$rootScope,confFactory ,accountFactory) {
				var monitor = __webpack_require__(306);
				console.debug('monitor', monitor);
				var service = {
					report: report,
					ID: 69373,
					PV: 0,
					FEEDBACK_COUNT: 1,
					EXCEPTION_COUNT: 2,
					INIT_EXCEPTION_COUNT: 3,
					QRCODE_EXCEPTION_COUNT: 4,
					AUTH_FAIL_COUNT: 5,
					ASSOCIATION_AUTH_COUNT: 6,
					ASSOCIATION_AUTH_FAIL_COUNT: 7,
					SEND_MSG_COUNT: 8,
					UPLOAD_COUNT: 9,
					UPLOAD_FAIL_COUNT: 10,
					CREATE_CHAT_ROOM_COUNT: 11,
					CREATE_CHAT_ROOM_FAIL_COUNT: 12,
					INVITE_TO_CHAT_ROOM_COUNT: 13,
					INVITE_TO_CHAT_ROOM_FAIL_COUNT: 14,
					CLICK_SNAPSHOT_COUNT: 15
				};
				function report (key, value, timeout) {
					if (!timeout) {
						timeout = 0;
					}
					monitor(service.ID, key, value, timeout);
				}
				return service;
			}]);
			})();
	
	/***/ }),
	/* 306 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function e(t,r){if(true)module.exports=r();else if(typeof define==="function"&&define.amd)define([],r);else if(typeof exports==="object")exports["monitor"]=r();else t["monitor"]=r()})(this,function(){return function(e){var t={};function r(n){if(t[n]){return t[n].exports}var u=t[n]={i:n,l:false,exports:{}};e[n].call(u.exports,u,u.exports,r);u.l=true;return u.exports}r.m=e;r.c=t;r.d=function(e,t,n){if(!r.o(e,t)){Object.defineProperty(e,t,{configurable:false,enumerable:true,get:n})}};r.n=function(e){var t=e&&e.__esModule?function t(){return e["default"]}:function t(){return e};r.d(t,"a",t);return t};r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};r.p="";return r(r.s=0)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:true});var n=r(1);var u=o(n);var i=r(2);var f=o(i);function o(e){return e&&e.__esModule?e:{default:e}}var a=(0,u.default)();var l=(0,u.default)();function d(e,t,r){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:0;var u=e+"-"+t;var i=a.get(u);if(i===undefined){a.set(u,r)}else{a.set(u,i+r)}var o=l.get(u);if(o===undefined){o=(0,f.default)(function(){var r=a.get(u);if(r!==undefined){var n="https://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportforweb?rid="+e+"&rkey="+t+"&rvalue="+r;(new Image).src=n;a.clear(u);l.clear(u)}},n,{leading:false});l.set(u,o)}o()}t.default=d;e.exports=t["default"]},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:true});var n=function e(){var t={};var r=function e(r){return t[r]};var n=function e(r,n){t[r]=n};var u=function e(r){if(r===undefined){t={}}else{t[r]=undefined}};return{get:r,set:n,clear:u}};t.default=n;e.exports=t["default"]},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:true});function n(e,t){var r=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};var n=void 0;var u=void 0;var i=void 0;var f=0;var o=function t(){f=r.leading===false?0:(new Date).getTime();n=null;e.apply(u,i);if(!n)u=i=null};var a=function a(){var l=(new Date).getTime();if(!f&&r.leading===false)f=l;var d=t-(l-f);u=this;i=arguments;if(d<=0||d>t){if(n){clearTimeout(n);n=null}f=l;e.apply(u,i);if(!n)u=i=null}else if(!n&&r.trailing!==false){n=setTimeout(o,d)}};return a}t.default=n;e.exports=t["default"]}])});
	
	/***/ }),
	/* 307 */
	/***/ (function(module, exports) {
	
		(function() {
			'use strict';
		
			/* Services */
		
			angular.module('Services')
			.factory('mmHttp', ['$http', '$q', '$timeout',function ($http, $q,$timeout) {
		
				var service = function(config){
					var method = config.method?config.method.toLowerCase():'get';
					var url = config.url;
					var data = config.data;
					var args = [url];
		
					data && args.push(data);
					args.push(config);
					return service[method].apply(service,args);
				};
		
				var methodList = ['post','get','jsonp'],method;
				for(var i = 0;i<methodList.length;i++){
					method = methodList[i];
					service[method]= (function(key){
						return function(url){
							var data,config;
							var args = [url];
							if(key=='post'){
								data=arguments[1];
								config = arguments[2];
							}else{
								config = arguments[1];
							}
		
							var mmRetry;
		
							data && args.push(data);
							if(config){
								mmRetry = typeof config.MMRetry != 'undefined';
								args.push(config);
							}
		
							var result;
		
							if(mmRetry){
								result = handlerRequest({
									args:args,
									method:key,
									config:config,
									data:{
										complete:false
									}
								});
							}else{
								result = $http[key].apply($http,args)
							}
		
							return result;
						}
					})(method)
				}
		
				// todo: 串行加载模式
				function handlerRequest(requestData){
					var data = requestData.data;
					var config = requestData.config;
					var mmRetry = config.MMRetry;
					var count = typeof mmRetry.count == 'undefined'?3:mmRetry.count;
					var timeout = mmRetry.timeout || 15000;
					var serial = mmRetry.serial;
					//回调列表，使得mmHttp支持类似 $http 的方式的链式添加 success 和 error 回调
					var successList  = [];
					var errorList = [];
		
					var retryCount = 0;
					var canceler = $q.defer();
					var completeCount = 0;
					config['timeout'] = canceler.promise;
					sendRequest(requestData.method,requestData.args);
					return {
						success:function(callback){
							successList.push(callback);
							return this;
						},
						error:function(callback){
							errorList.push(callback);
							return this;
						}
					};
		
					function sendRequest(method,args){
		
						$http[method].apply($http,args).success(requestSuccess).error(requestError);
						$timeout(function(){
							if(!data.complete){
								retry();
							}
						},timeout);
					}
					function runCallback(list,self,args){
						for(var i = 0 ;i<list.length;i++){
							list[i].apply(self,args);
						}
					}
					function requestSuccess(){
						completeCount++;
						if(!data.complete){
							// canceler 不能保证必定不会执行多次成功回调，只能用做节省请求资源， complete 参数保证回调一定不会执行多次
							data.complete = true;
							canceler.resolve();
							runCallback(successList,this,arguments);
						}
					}
					function requestError(err){
						completeCount++;
						if(!retry() && !data.complete && completeCount == count+1){
							runCallback(errorList,this,arguments);
						}
					}
					function retry(){
						if(retryCount >= count || data.complete){
							return false;
						}else{
		
							if(serial){
								canceler.resolve();
								canceler = $q.defer();
								config['timeout'] = canceler.promise;
							}
		
							retryCount ++;
							sendRequest(requestData.method,requestData.args);
							return true;
						}
					}
				}
		
		
				return service;
			}]);
		
		})()
	
	/***/ }),
	/* 308 */
	/***/ (function(module, exports) {
	
		(function() {
			'use strict';
		
			/* Services */
		
			angular.module('Services')
				.factory('surviveCheckService', ['$http', '$q', '$timeout',function ($http, $q,$timeout) {
				   var timer ;
				   var callback
				   var service = {
					   start:function(time){
						   if(timer) clearInterval(timer);
		
						   timer = setInterval(function(){
							   callback && callback();
						   },time)
					   },
					   stop:function(){
						   if(timer) clearInterval(timer);
					   },
					   callback:function(cb){
						   callback = cb;
					   }
				   }
		
					return service;
				}]);
		
		})()
	
	/***/ }),
	/* 309 */
	/***/ (function(module, exports) {
	
		(function (_aoUndefined) {
			'use strict';
		
			/* Services */
		
			angular.module('Services')
				.factory('titleRemind', [
					'$window',
					'confFactory',
					function ($window,confFactory) {
						var active = true;
						var document = $window.document;
						/*$(window).focus(function() { active = true; MsgRemind.stop();});
						 $(window).blur(function() { active = false;MsgRemind.start();});*/
		
		
						var MsgRemind = {
							defaultTitle: confFactory.isClientVersion?_("cfbf6f4"):_("2f521c5"),
							unreadMsgNum: 0,
							start: function () {
								var self = this;
								this.unreadMsgNum = 0;
								this.timer && clearTimeout(this.timer);
								this.timer = setTimeout(function toggle () {
									self._toggle();
									self.timer = setTimeout(toggle,2000);
								}, 2000)
							},
							_toggle: function () {
		
								if (document.title == this.defaultTitle && this.unreadMsgNum > 0) {
									document.title = _("cfbf6f4") + '(' + this.unreadMsgNum + ')';
								} else {
									document.title = this.defaultTitle;
								}
		
							},
							stop: function () {
								var self = this;
								this.timer && clearTimeout(this.timer);
								setTimeout(function(){
									document.title =  self.defaultTitle;
								},100)
		
							},
							increaseUnreadMsgNum: function () {
								if (active) return;
								this.unreadMsgNum++;
							}
		
						}
		
						bindEvent(function(){
							active = false;MsgRemind.start();
						},function(){
							active = true; MsgRemind.stop();
						});
						function bindEvent(start, stop) {
							var hidden, visibilityChange;
							if (typeof document.hidden !== "undefined") {
								hidden = "hidden";
								visibilityChange = "visibilitychange";
							} else if (typeof document.mozHidden !== "undefined") {
								hidden = "mozHidden";
								visibilityChange = "mozvisibilitychange";
							} else if (typeof document.msHidden !== "undefined") {
								hidden = "msHidden";
								visibilityChange = "msvisibilitychange";
							} else if (typeof document.webkitHidden !== "undefined") {
								hidden = "webkitHidden";
								visibilityChange = "webkitvisibilitychange";
							}
		
		
							function handleVisibilityChange() {
								if (document[hidden]) {
									start();
								} else {
									stop();
								}
							}
		
							if (typeof document.addEventListener === "undefined" || typeof hidden === "undefined") {
								$(window).focus(function () {
									stop();
								});
								$(window).blur(function () {
									start();
								});
		
							} else {
								document.addEventListener(visibilityChange, handleVisibilityChange, false);
							}
						}
		
		
						var service = {
							increaseUnreadMsgNum: function () {
								MsgRemind.increaseUnreadMsgNum();
							}
						}
						return service;
					}]);
		})();
	
	
	/***/ }),
	/* 310 */
	/***/ (function(module, exports) {
	
		(function(_aoUndefined){
			'use strict';
		
			/* Services */
		
			angular.module('Services')
				.factory('subscribeMsgService', [
					'$rootScope',
					'contactFactory',
					'accountFactory',
					'confFactory',
					'utilFactory',
					function($rootScope, contactFactory,accountFactory, confFactory,utilFactory) {
						var subscribeMsgs=[];
		
		
		
						var service = {
							current:null,
							changeFlag : 0,
							init:function(list){
								//if(list.length>0){
								//    this.changeFlag = Date.now();
								//}
		
								this.changeFlag = Date.now();
		
								this.add(list);
		
		
							},
							getSubscribeMsgs:function(){
							  return subscribeMsgs;
							},
							add:function(list){
								if(list.length>0) this.changeFlag = Date.now();
		
								for(var i = 0, len = list.length; i < len; i++){
									var item = list[i];
									//item.Cover = item.Cover.replace(/^http:\/\//, 'https://');
									/*   item.Url = item.Url.replace(/^http:\/\//, 'https://');*/
		
		
		
									item.HeadImgUrl = item.HeadImgUrl = utilFactory.getContactHeadImgUrl({
										UserName:item.UserName,
										Skey:accountFactory.getSkey()
									});
									var articleList =item.MPArticleList;
									for(var j = 0;j<articleList.length;j++){
										var article = articleList[j];
										article.AppName = item.NickName;
									 
										if (!/dev\.web\.weixin/.test(location.href)){
											article.Url = article.Url.replace(/^http:\/\//, 'https://');
										}
									}
		
									subscribeMsgs.push(item)
								}
		
		
							}
						};
						return service;
		
					}]);
		})();
	
	
	/***/ }),
	/* 311 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Directives */
		
		angular.module('Directives')
		.directive('messageDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				templateUrl: 'message.html',
				link: function (scope, element, attrs) {
					//console.log('msgTextDirective');
				}
			};
		}]);
		
		})();
	
	/***/ }),
	/* 312 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('ngInput', ['$parse',function($parse) {
			return function(scope, element, attrs) {
				var fn = $parse(attrs.ngInput);
				element.bind('input propertychange', function(event) {
					if(!scope.$$phase) {
						scope.$apply(function() {
							fn(scope, {$event:event});
						});
					}else{
						fn(scope, {$event:event});
					}
				});
			};
		}]);
	
	/***/ }),
	/* 313 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('ngRightClick', ['$parse',function($parse) {
			return function(scope, element, attrs) {
				var fn = $parse(attrs.ngRightClick);
				element.bind('contextmenu', function(event) {
					scope.$apply(function() {
						//event.preventDefault();
						fn(scope, {$event:event});
					});
				});
			};
		}]);
	
	/***/ }),
	/* 314 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('mmpopDirective', ['$timeout', '$document', 'mmpop','$animate',function($timeout, $document, mmpop, $animate) {
			return {
				restrict: 'EA',
				scope: {},
				link: function(scope, element, attrs) {}
			};
		}])
		.provider('mmpop',function() {
			var $el = angular.element;
			var isDef = angular.isDefined;
			var style = (document.body || document.documentElement).style;
			var defaults = this.defaults = {
				className: '',
				plain: false,
				showClose: true,
				closeByEscape: true,
				cache: true,
				autoFoucs:true,
				stopPropagation:true
			};
		
		
			this.setDefaults = function (newDefaults) {
				angular.extend(defaults, newDefaults);
			};
		
			var globalID = 0, popsCount = 0, defers = {};
		
			this.$get = ['$document', '$templateCache', '$compile', '$q', '$http', '$rootScope', '$timeout', '$window', '$controller','$animate',
				function ($document, $templateCache, $compile, $q, $http, $rootScope, $timeout, $window, $controller,$animate) {
					var $body = $document.find('body');
					var privateMethods = {
						onDocumentKeydown: function (event) {
							if (event.keyCode === 27) {
								publicMethods.close('$escape');
							}
						},
		
						performClosePop: function ($pop, value) {
							var id = $pop.attr('id'),
								mmpopScope = $pop.scope();
		
							if(!mmpopScope || mmpopScope.closing) return;
		
							mmpopScope.closing = true;
							$pop.unbind('click');
		
							if (popsCount === 1) {
								$body.unbind('keydown');
							}
		
							$rootScope.$broadcast('root:mmpop:closing', id);
							$animate.leave($pop,function(){
								if(mmpopScope){
									$rootScope.$broadcast('root:mmpop:closed', id);
									$document.unbind('click',mmpopScope.closeThisMmPop);
									mmpopScope.$destroy();
								}
							});
		
							if (defers[id]) {
								defers[id].resolve({
									id: id,
									value: value,
									$pop: $pop,
									remainingPops: popsCount
								});
								delete defers[id];
							}
						},
		
						closePop: function ($pop, value) {
							privateMethods.performClosePop($pop, value);
						}
					};
		
					var publicMethods = {
		
						/**
						 * [创建mmpop]
						 * @param  {object} options
						 * @param  {object.template}        模版字符串
						 * @param  {object.templateUrl}     模版路径或ID
						 * @param  {object.className}       css扩展类
						 * @param  {object.container}       容器
						 * @param  {object.top}    
						 * @param  {object.left}
						 * @param  {object.autoFoucs}       是否自动获取鼠标焦点，默认为true
						 * @param  {object.singletonId}     单例id
						 */
						open: function (opts) {
							var self = this;
							var options = angular.copy(defaults);
		
							opts = opts || {};
							angular.extend(options, opts);
		
							globalID += 1;
		
							self.latestID = 'ngpop' + globalID;
		
							if(options.singletonId){
								//console.log('publicMethods.close',options.singletonId);
								if(document.getElementById(options.singletonId)){
									publicMethods.close(options.singletonId);
								}
							}
		
							var mmpopId = options.singletonId || ('mmpop' + globalID);
		
							$rootScope.$broadcast('root:mmpop:open', mmpopId);
		
							var defer;
							defers[self.latestID] = defer = $q.defer();
		
							//var scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();
							var scope;
							if(options.scope){
								if(options.scope.$new){
									scope = options.scope.$new();
								}else{
									scope = $rootScope.$new();
									angular.extend(scope,options.scope);
								}
							}else{
								scope = $rootScope.$new();
							}
		
							var $pop, $popParent;
		
							//$q.when(loadTemplate(options.template || options.templateUrl)).then(function (template) {
		
								//$templateCache.put(options.template || options.templateUrl, template);
								if(options.template){
								  template = options.template;
								}else if(options.templateUrl){
								  template =  $templateCache.get(options.templateUrl);
								}
		
								self.$result = $pop = $el('<div id="' + mmpopId + '" class="mmpop" tabindex="-1"></div>');
								$pop.html(template);
		
								if (options.data && angular.isString(options.data)) {
									var firstLetter = options.data.replace(/^\s*/, '')[0];
									scope.mmpopData = (firstLetter === '{' || firstLetter === '[') ? angular.fromJson(options.data) : options.data;
								} else if (options.data && angular.isObject(options.data)) {
									scope.mmpopData = options.data;
								}
		
								if (options.container/* && angular.isString(options.container)*/) {
									//$popParent = angular.element(document.querySelector(options.container));
									$popParent = options.container;
								} else {
									$popParent = $body;
								}
								
								//$timeout(function () {
									$compile($pop)(scope);
		
									//$popParent.append($pop);
									$animate.enter($pop,$popParent);
									if(options.autoFoucs){
										$pop.focus();
										//console.log('focus',$pop);
									}
								//});
		
								if (options.controller && (angular.isString(options.controller) || angular.isArray(options.controller) || angular.isFunction(options.controller))) {
									var controllerInstance = $controller(options.controller, {
										$scope: scope,
										$element: $pop
									});
								}
		
								if (options.className) {
									$pop.addClass(options.className);
								}
		
								if (options.top){
									$pop.css('top',options.top);
								}
		
								if (options.left){
									$pop.css('left',options.left);
								}
		
								scope.closeThisMmPop = function (value) {
									setTimeout(function(){
										if(value && value.target && (value.target.id == mmpopId || ($pop[0] && jQuery.contains($pop[0],value.target)))) return;
										privateMethods.closePop($pop, value);
										scope.$digest();
									},0);
								};
		
								$pop.bind('click',function(e) {
									if(options.stopPropagation){
										e.preventDefault();
										e.stopPropagation();
									}
								});
		
								$timeout(function () {
									$document.bind('click', scope.closeThisMmPop);
								},0);
		
								if (options.closeByEscape) {
									$body.bind('keydown', privateMethods.onDocumentKeydown);
								}
		
								popsCount += 1;
		
								//return publicMethods;
							//});
		
							return {
								close:scope.closeThisMmPop,
								isOpen:function(){
									return $el(document.getElementById(mmpopId)).length;
								}
							};
		
							function loadTemplateUrl (tmpl, config) {
								return $http.get(tmpl, (config || {})).then(function(res) {
									return res.data || '';
								});
							}
		
							function loadTemplate (tmpl) {
								if (!tmpl) {
									return 'Empty template';
								}
		
								if (angular.isString(tmpl) && options.plain) {
									return tmpl;
								}
		
								if (typeof options.cache === 'boolean' && !options.cache) {
									return loadTemplateUrl(tmpl, {cache: false});
								}
		
								return $templateCache.get(tmpl) || loadTemplateUrl(tmpl, {cache: true});
							}
						},
		
						toggleOpen: function (options) {
							if(!options.singletonId){ console.error('toggleOpen function require singletonId.');return;}
							var el = document.getElementById(options.singletonId);
							if(el){
								//this.close(options.singletonId);
							}else{
								this.open(options);
							}
						},
		
						/*
						 * @param {String} id
						 * @return {Object} pop
						 */
						close: function (id, value) {
							var $pop = $el(document.getElementById(id));
		
							if ($pop.length) {
								privateMethods.closePop($pop, value);
							} else {
								publicMethods.closeAll(value);
							}
		
							return publicMethods;
						},
		
						closeAll: function (value) {
							var $all = document.querySelectorAll('.mmpop');
		
							angular.forEach($all, function (pop) {
								privateMethods.closePop($el(pop), value);
							});
						}
					};
		
					return publicMethods;
				}];
		});
	
	/***/ }),
	/* 315 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('contenteditableDirective', ['$timeout', 'utilFactory', 'confFactory', function ($timeout, utilFactory, confFactory) {
			return {
				restrict: 'A',
				require: '?ngModel',
				link: function (scope, element, attrs, ngModel) {
					// don't do anything unless this is actually bound to a model
					if (!ngModel) {
						return
					}
		
					var cleanHTMLTimeout;
					element.bind('paste', function(){
						var ele = this;
						var before = ele.innerHTML;
						if(cleanHTMLTimeout) clearTimeout(cleanHTMLTimeout);
						cleanHTMLTimeout = setTimeout(function () {
							// 计算粘贴后html不同的位置起点和终点（插入"abc"，则得出sPos为0，ePos为2）
							var after = ele.innerHTML, sPos = -1, ePos = -1;
							for (var i = 0, len = after.length; i < len; ++i) {
								if (sPos == -1 && before.substr(i, 1) != after.substr(i, 1)) sPos = i;
								if (ePos == -1 && before.substr(before.length - i - 1, 1) != after.substr(after.length - i - 1, 1)) ePos = i;
		
								if(sPos != -1 && ePos != -1 || len - 1 - ePos <= sPos) break;
							}
							if(sPos == -1 || ePos == -1) return;
							ePos = len - 1 - ePos;
		
							if(ePos <= sPos){ // 遇到像ab，粘贴ab后变成abab这种了，这是需要从sPos开始往后找，找到和before一样的为止
								i = sPos;
								var beforeSPosNext = before.substr(i + 1, 10); // 取后10个来对比，如果没有10个，则取最多
								while(++i < len){
									if (beforeSPosNext == after.substr(i, beforeSPosNext.length)) {
										ePos = i;
										break;
									}
								}
								i == len && (ePos = len - 1);
							}
							// 如果有<和>，则需要计算在内
							if(after.substr(sPos - 1, 1) == "<") --sPos;
							if(after.substr(ePos + 1, 1) == ">") ++ePos;
		
							// 分段获得文本，前半段 插入段 后半段
							var pastedText = after.substring(sPos, ePos + 1),
								formerText = after.substr(0, sPos),
								latterText = after.substr(sPos + pastedText.length);
		
							// 判断formerText和pastedText是否闭合了
							var lastLT = formerText.lastIndexOf("<"), lastGT = formerText.lastIndexOf(">");
							if(lastGT < lastLT){ // 标签断了xxxxx<
								pastedText = formerText.slice(lastLT) + pastedText;
								formerText = formerText.slice(0, lastLT);
							}
		
							lastLT = pastedText.lastIndexOf("<");
							lastGT = pastedText.lastIndexOf(">");
							if(lastGT < lastLT){ // 标签断了<xxxxxx
								var _insertGT = latterText.indexOf(">") + 1;
								pastedText += latterText.slice(0, _insertGT);
								latterText = latterText.slice(_insertGT);
							}
		
							var insertText = retainFormat(pastedText)
								.replace(/&nbsp;/g, " ") // 替换空格
								.replace(new RegExp("<(?!br|" + confFactory.EMOTICON_REG + ").*?>", "g"), "") // 洗掉各种属性和标签，除了<br>和表情的<img>
								.replace(new RegExp("&lt;(br|" + confFactory.EMOTICON_REG + "\/?)&gt;", "g"), "<$1>")// <br> 或 <img class="emoji emoji11" text="[..]" src=".." />
								.replace(/<img.*?class="(.*?)" text="(.*?)" .*?>/g, function () {
									return utilFactory.genEmoticonHTML(arguments[1], arguments[2])
								})
								.replace(/<img [^<>]*src="([^<>"]+)"[^<>]*>/g,function(str,srcStr){
									return str.replace(location.origin || location.protocol + "//" + location.hostname + (location.port ? ':' + location.port: ''), ""); // 把当前的绝对地址替换成相对，避免被link化
								})
		
							ele.innerHTML = formerText + insertText + "<span class='pasteCaretPosHelper'></span>" + latterText; // 插入pasteCaretPosHelper以帮助定位光标位置
		
							var pasteCaretPosHelper = element.find(".pasteCaretPosHelper")[0], range,selection;
							if(pasteCaretPosHelper){
								if(document.createRange){ // Chrome, IE 9+
									range = document.createRange();
									range.setStartAfter(pasteCaretPosHelper);
									range.collapse(false);
									selection = window.getSelection();
									selection.removeAllRanges();
									selection.addRange(range);
								}else if(document.selection){ // IE 8 and lower
									range = document.body.createTextRange();
									range.moveToElementText(pasteCaretPosHelper);
									range.collapse(false);
									range.select();
								}
								pasteCaretPosHelper.parentNode.removeChild(pasteCaretPosHelper);
							}
		
							ngModel.$setViewValue(formerText + insertText + latterText);
							cleanHTMLTimeout = null;
						}, 50);
					});
		
		
					function retainFormat(str){
		
						return str.replace(new RegExp("^(<(table|tbody|p|tr|h[1-6])[^<>]*>)+", "g"),'')
							 .replace(new RegExp("<td[^<>]*>(<(table|tbody|p|tr|h[1-6])[^<>]*>)*|(</(table|tbody|p|h[1-6])>)*</td>", "g"),'  ')
							.replace(new RegExp("(</(table|tbody|p|tr|h[1-6])>+)<(table|tbody|p|tr|h[1-6])[^<>]*>+", "g"), "<br/>")
							.replace(new RegExp("(<(table|tbody|p|tr|h[1-6])[^<>]*>)+|(</(table|tbody|p|tr|h[1-6])>)+", "g"), "<br/>")
					}
		
					// view -> model
					function _view2Model(){
						scope.$apply(function () {
							var html;
							html = element.html();
							ngModel.$setViewValue(html);
		
							//if (html === '') {// the cursor disappears if the contents is empty, so we need to refocus
							//    $timeout(function () {
							//        element[0].blur();
							//        element[0].focus();
							//    })
							//}
						});
					}
					if(utilFactory.browser.msie) element.bind('keyup paste', _view2Model);
					else element.bind('input', _view2Model);
		
					// model -> view
					var oldRender = ngModel.$render;
					ngModel.$render = function () {
						if (!!oldRender) {
							oldRender();
						}
						if(element.html() != ngModel.$viewValue) element.html(ngModel.$viewValue || '');
					};
				}
			}
		}]);
	
	/***/ }),
	/* 316 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Directives')
		.directive('miniUserProfileDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				templateUrl:'miniUserProfile.html',
				scope:{
				   user:"=",
				   showOrderc:"=",
				   hasCheckbox:"=",
				   selectedUsers:"=",
				   clickUserCallback:"="
				},
				link: function (scope, element, attrs) {
					//console.log('msgTextDirective');
				}
			};
		}])
		.directive('userProfileDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				scope:{
				   user:"="
				},
				templateUrl:'userProfile.html',
				link: function (scope, element, attrs) {
				}
			};
		}]);
		
		})();
	
	/***/ }),
	/* 317 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Directives')
		.directive('contactListDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				templateUrl: 'contactList.html',
				replace:true,
				scope:{
				   currentContact:"=",
				   starContacts:"=",
				   chatroomContacts:"=",
				   friendContacts:"=",
				   clickUserCallback:"=",
				   allContacts:"=",
				   dblclickCallback:"=",
					heightCalc:"=?"
				},
				link: function (scope, element, attrs) {
					console.log('allContact',scope.allContacts);
					scope.heightCalc = scope.heightCalc ||function(item){
						if(item.type === 'header'){
							return 24;
						}else{
							return 50;
						}
					}
				}
			};
		}])
		.directive('contactListChooserDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				templateUrl: 'contactListChooser.html',
				replace:true,
				scope:{
				   starContacts:"=",
				   chatroomContacts:"=",
				   friendContacts:"=",
				   selectedUsers:"=",
				   isCheck:"=",
				   allContacts:"=",
				   clickUserCallback:"="
				},
				link: function (scope, element, attrs) {
					//console.log('msgTextDirective');
					scope.heightCalc = function(item){
						if(item.type === 'header'){
							return 32;
						}else{
							return 62;
						}
					}
					scope.mmRepeatKeyboard.start();
		
					scope.$watch(function () {
						return scope.allContacts;
					}, function (newValue) {
						if(!scope.current && newValue.length > 0){
							scope.current =scope.allContacts[0];
							scope.mmRepeatKeyboard.setSelectItem(scope.current);
						}
					});
		
					scope.mmRepeatKeyboard.setJudgeFun(function(item){
						return item.UserName;
					})
		
					scope.$on('mmrepeat:select',function(e,item){
						scope.current = item;
						scope.$digest();
					});
		
		
		
				}
			};
		}]);
		
		})();
	
	/***/ }),
	/* 318 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Directives')
		.directive('contactItemDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				templateUrl: 'contactItem.html',
				replace:true,
				scope:{
				   className: "@",
				   user:"=",
				   showOrderSymbol:"=",
				   orderSymbol:"=",
				   clickUserCallback:"="
				},
				link: function (scope, element, attrs) {
					//console.log('msgTextDirective');
				}
			};
		}])
		.directive('contactItemChooserDirective',['$timeout','confFactory',function($timeout,confFactory) {
			return {
				restrict: 'A',
				templateUrl: 'contactItemChooser.html',
				scope:{
				   user:"=",
				   showOrderSymbol:"=",
				   orderSymbol:"=",
				   isCheck:"=",
				   clickUserCallback:"="
				},
				link: function (scope, element, attrs) {
					//console.log('msgTextDirective');
				}
			};
		}]);
		
		})();
	
	/***/ }),
	/* 319 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Directives')
		.directive('contextMenuDirective',['$timeout','$document','confFactory',function($timeout,$document,confFactory) {
			return {
				restrict: 'A',
				templateUrl: 'contextMenu.html',
				replace:true,
				scope:{},
				controller:'contextMenuController',
				link: function (scope, element, attrs) {
					/*function removeElement () {
					  element.css("display","none");
					}
					$timeout(function () {
					  $document.bind('click', removeElement);
					  scope.$on('$destroy', function(){
						$document.unbind('click', removeElement);
					  });
					},0);*/
				}
			};
		}]);
		
		})();
	
	/***/ }),
	/* 320 */
	/***/ (function(module, exports) {
	
		/**
		 * https://github.com/Luegg/angularjs-scroll-glue
		 */
		(function(angular, undefined){
			'use strict';
		
			angular.module('Directives')
			.directive('scrollGlue', ['$parse','$timeout', function($parse,$timeout){
				function unboundState(initValue){
					var activated = initValue;
					return {
						getValue: function(){
							return activated;
						},
						setValue: function(value){
							activated = value;
						}
					};
				}
		
				function oneWayBindingState(getter, scope){
					return {
						getValue: function(){
							return getter(scope);
						},
						setValue: function(){}
					}
				}
		
				function twoWayBindingState(getter, setter, scope){
					return {
						getValue: function(){
							return getter(scope);
						},
						setValue: function(value){
							if(value !== getter(scope)){
								scope.$apply(function(){
									setter(scope, value);
								});
							}
						}
					};
				}
		
				function createActivationState(attr, scope){
					if(attr !== ""){
						var getter = $parse(attr);
						if(getter.assign !== undefined){
							return twoWayBindingState(getter, getter.assign, scope);
						} else {
							return oneWayBindingState(getter, scope);
						}
					} else {
						return unboundState(true);
					}
				}
		
				return {
					priority: 1,
					restrict: 'A',
					link: function(scope, $el, attrs){
						var el = $el[0],
							activationState = createActivationState(attrs.scrollGlue, scope);
		
						function scrollToBottom(){
		
							el.scrollTop = el.scrollHeight;
						}
		
						function onScopeChanges(scope){
							console.log('scrollTobottom',activationState.getValue())
							if(activationState.getValue()){
								scrollToBottom();
							}
						}
		
						function shouldActivateAutoScroll(){
							// + 1 catches off by one errors in chrome
							console.log(el.scrollTop, el.clientHeight,el.scrollHeight)
							return el.scrollTop + el.clientHeight + 1 >= el.scrollHeight;
						}
		
						function onScroll(){
							$timeout(function(){
								activationState.setValue(shouldActivateAutoScroll());
							},3);
						}
		
						scope.$watch(onScopeChanges);
						$el.bind('scroll', onScroll);
					}
				};
			}]);
		}(angular));
	
	/***/ }),
	/* 321 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function(undefined){
			'use strict';
		
			/* Services */
		
			angular.module('Directives')
				.directive('jplayerDirective', ['$timeout','utilFactory',function ($timeout,utilFactory) {
					return {
						restrict: 'A',
						link: function (scope, element, attrs) {
							scope.loaded = false;
		
							var timer,
								timeout = attrs.lenght || 6100,
								useFlash = (utilFactory.browser.msie || utilFactory.browser.safari);
		
							if(attrs.timeout){
								setTimeout(function(){
									init();
								},+attrs.timeout);
							}else{
								init();
							}
		
							function init(){
								__webpack_require__.e/* nsure */(2/* duplicate */, function (require) {
									var jplayer = __webpack_require__(278);
									jQuery(element).jPlayer({
										ready: function () {
											//jQuery(element).append('<i class="web_wechat_paly"></i>');
											jQuery(this).jPlayer("setMedia", {
												m4v: attrs.src + (useFlash ? '&type=flv' : ''),
												poster: attrs.poster
											});
											if (attrs.muted !== undefined) {
												jQuery(this).jPlayer("mute");
											}
											if (attrs.loop !== undefined && useFlash) {//jplayer 在flash模式下loop不生效，使用timer实现loop
												jQuery(this).jPlayer("play");
												flashLoop();
											}
										},
										click: function () {
											// 点击flash不触发ng-click，需要手动触发
											if (utilFactory.browser.msie) {
												jQuery(this).click();
											}
										},
										loadstart: function () {
											console.log('loadstart ');
										},
										progress: function () {
											console.log('progress ');
										},
										play: function () {
											if (useFlash) {
												scope.loaded = true;
												scope.$digest();
											}
											console.log('play ');
										},
										loadedmetadata: function () {
											jQuery(this).jPlayer("play");
											console.log('loadedmetadata ');
										},
										playing: function () {
											scope.loaded = true;
											scope.$digest();
											console.log('playing ');
										},
										seeked: function () {
											console.log('seeked  ');
										},
										seeking: function () {
											console.log('seeking ');
										},
										swfPath: window.MMSource.jplayerSwfPath,
										solution: useFlash ? "flash" : "html,flash",
										supplied: "webmv, ogv, m4v",
										backgroundColor: '#000000',
										loop: attrs.loop !== undefined,
										size: {
											width: scope.width || "200px",
											height: scope.height || "150px",
											cssClass: "jp-video-360p"
										}
									});
		
									scope.$on('$destroy', function () {
										cleanTimer();
										jQuery(element).jPlayer("destroy")
									});
								});
							}
		
							function flashLoop(){
								cleanTimer();
								timer = $timeout(function(){
									jQuery(element).jPlayer( "stop" );
									jQuery(element).jPlayer("play");
									flashLoop();
								},timeout);
							}
							function cleanTimer(){
								timer && $timeout.cancel(timer);
							}
		
						}
					};
				}]);
		
		})();
	
	
	/***/ }),
	/* 322 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('previewDirective', ['$document', 'confFactory', 'utilFactory',function( $document, confFactory, utilFactory) {
			return {
				restrict: 'EA',
				templateUrl:'preview.html',
				scope: {
					imageList:'=',
					current:'='
				},
				link: function(scope, element, attrs) {
					var imgWrp$ = element.find("#img_dom"), imgOprWrp$ = element.find("#img_opr_container"), imgPreview$ = imgWrp$.find("#img_preview"),
						previewWidth = document.documentElement.clientWidth,
						previewHeight = document.documentElement.clientHeight - parseInt(imgOprWrp$.css("bottom")) - parseInt(imgOprWrp$.height());
					scope.isLoaded = false; // 大图是否加载完成
					scope.rotateDeg = 0;
					scope.isIE = !!(utilFactory.browser.msie && utilFactory.version < 10);
					scope.actions = {
						next: function(){
							if(scope.current < scope.imageList.length - 1){
								scope.current++;
								loadImg();
							}
						},
						prev: function(){
							if(scope.current > 0){
								scope.current--;
								loadImg();
							}
						},
						rotate: function(){
							scope.rotateDeg = (scope.rotateDeg + 90) % 360;
							zoom({scale: imgInitData.scale});
							move({ // 屏幕居中
								top: (previewHeight - imgData.height) / 2,
								left: (previewWidth - imgData.width) / 2
							});
		
							// webkit 的 transform 有导致不 reflow 的bug，强行改变其子元素来强制reflow
							scope.reflowFlag = !scope.reflowFlag;
						},
						close: function(){
							element.remove();
							scope.$destroy()
						}
					};
					scope.$on('$destroy',function() {
						$document.unbind('keyup', keyup);
						$document.unbind('keydown', keydown);
					});
		
		
					// 处理键盘事件
					function keyup(e){
						switch(e.keyCode){
							case confFactory.KEYCODE_ARROW_UP:
							case confFactory.KEYCODE_ARROW_LEFT:
								scope.actions.prev();
								break;
							case confFactory.KEYCODE_ARROW_DOWN:
							case confFactory.KEYCODE_ARROW_RIGHT:
								scope.actions.next();
								break;
							case confFactory.KEYCODE_ESC:
								scope.actions.close();
								break;
						}
						scope.$digest();
						e.preventDefault();
						e.stopPropagation();
					}
					function keydown(e){
						switch(e.keyCode){
							case confFactory.KEYCODE_NUM_ADD:
							case confFactory.KEYCODE_ADD:
								zoom({delta: 1});
								break;
							case confFactory.KEYCODE_NUM_MINUS:
							case confFactory.KEYCODE_MINUS:
								zoom({delta: -1});
								break;
						}
		
						e.preventDefault();
						e.stopPropagation();
					}
					$document.keyup(keyup);
		
		
					// 图片移动与缩放
					var
						SCALE_LIMIT = 5, // 缩放倍数的上限
						SCALE_STEP = 0.1, // 每次缩放倍数
		
						imgInitMaxWidth = previewWidth * 0.8, // 图片初始显示的最大宽度（区域的80%）
						imgInitMaxHeight = previewHeight * 0.8, // 图片初始显示的最大高度（区域的80%）
						imgOriginSize, // 图片原始大小
						imgInitData = {}, // 图片一开始展现时的数据 {width, height, top, left, scale}
						imgData,// 当前图片的状态 {width, height, top, left, scale}
		
						isFirefox = document.mozHidden !== undefined,
						mousewheleEvent = isFirefox ? "DOMMouseScroll" : "mousewheel", // FF的mousewheel事件兼容
		
						mousedownPos,// 鼠标按下时的坐标 {x, y}
						imgPosBeforeMove; // 图片移动前的坐标 {top, left}
		
					/**
					 * 图片缩放，原理：保持缩放点在图中的比例不变，可以传两种参数
					 * 第一种：opt {delta[, posRatio]} delta 滚轮方向； posRatio 缩放点在原图的位置比例（不传，默认{x:0.5, y:0.5}，即中点）
					 * 第二种：opt {scale} scale缩放的比例，如果有，则按此比例进行缩放
					 */
					function zoom(opt){
						var scale, posRatio;
						if(opt.scale){
							scale = opt.scale;
							posRatio = {x: 0.5, y: 0.5};
						}else{
							var delta = opt.delta;
							posRatio = opt.posRatio || {x:0.5, y:0.5};
							scale = imgData.scale;
		
							scale = delta > 0 ? (scale + SCALE_STEP) : (scale - SCALE_STEP);
						}
						scale = scale > SCALE_LIMIT ? SCALE_LIMIT : scale < 1 / SCALE_LIMIT ? 1 / SCALE_LIMIT : scale;
		
						var newData = {
							width: Math.round(imgOriginSize.width * scale),
							height: Math.round(imgOriginSize.height * scale),
							scale: scale
						};
						newData.top = Math.round(imgData.top - posRatio.y * (newData.height - imgData.height));
						newData.left = Math.round(imgData.left - posRatio.x * (newData.width - imgData.width));
		
						imgData = newData;
						imgWrp$.css(newData);
					}
					/**
					 * 移动图片
					 */
					function move(pos){
						angular.extend(imgData, pos);
						imgWrp$.css(pos);
					}
					/**
					 * 事件绑定
					 */
					function _mousemove(e){
						move({
							top: e.clientY - mousedownPos.y + imgPosBeforeMove.top,
							left: e.clientX - mousedownPos.x + imgPosBeforeMove.left
						});
						e.preventDefault();
					}
					function bindEvent(){
						imgWrp$.on("mousedown", function (e) {
							if(isFirefox){ // FF下拖动会导致新开窗口
								scope.actions.close();
								return;
							}
							mousedownPos = {x: e.clientX, y: e.clientY};
							imgPosBeforeMove = {top: imgData.top, left: imgData.left};
		
							imgOprWrp$.css("display", "none");
							imgWrp$.on("mousemove", _mousemove);
							e.stopPropagation();
						}).on("mouseup", function () {
							imgWrp$.off("mousemove", _mousemove);
		
							imgOprWrp$.css("display", "block");
						}).on(mousewheleEvent, function(evt){
							var e = evt.originalEvent, delta;
							if (e.type == 'mousewheel' || e.type == 'DOMMouseScroll') {
								delta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
							}
							if(delta === undefined) return;
							zoom(isFirefox ? {delta: delta} : { // FF因为不能拖动，所以只沿中点放大
								delta: delta,
								posRatio: {
									x: e.offsetX / imgData.width,
									y: e.offsetY / imgData.height
								}
							});
		
							evt.preventDefault();
							evt.stopPropagation();
						});
						$document.keydown(keydown);
					}
					/**
					 * 加载大图
					 */
					function loadImg(){
						var preview = scope.imageList[scope.current].preview;
						scope.isLoaded = false;
						scope.rotateDeg = 0;
		
						if(preview){
							scope.containerStyle = {
								'background':'url('+preview+') no-repeat center center',
								'background-size':'auto'
							}  ;
						}
		
		
						// 大图的加载
						var img = new Image();
						img.onload = function(){
							img.onload = null;
		
							imgOriginSize = {width: img.width, height:img.height};
							imgData = {
								width: imgOriginSize.width,
								height: imgOriginSize.height,
								top: (previewHeight - imgOriginSize.height) / 2,
								left: (previewWidth - imgOriginSize.width) / 2,
								scale: 1
							};
		
							// 如果图片超过最大宽度，进行缩放
							var heightScale = imgInitMaxHeight / img.height,
								widthScale = imgInitMaxWidth / img.width;
							if(heightScale < 1 && widthScale < 1){
								zoom({scale: heightScale < widthScale ? heightScale : widthScale});
							}else if(heightScale < 1){
								zoom({scale: heightScale});
							}else if(widthScale < 1){
								zoom({scale :widthScale});
							}else{
								imgWrp$.css(imgData);
							}
							angular.extend(imgInitData, imgData);
		
							imgPreview$[0].src = img.src;
							scope.isLoaded = true;
							scope.containerStyle = null;
							scope.$digest();
						};
						img.onerror = function(){
							img.onerror = null;
							alert(_("845ec73"));
						};
						img.src = scope.imageList[scope.current].url;
					}
		
		
					// 点击空白关闭
					imgWrp$.on("click", function(e){
						e.stopPropagation();
					});
					imgOprWrp$.on("click", function(e){
						e.stopPropagation();
					});
					$("#preview_container").on("click", function(e){
						scope.actions.close();
					});
		
		
					// 初始化
					bindEvent();
					loadImg();
				}
			};
		}])
		.provider('preview',function() {
			return {
				$get: ['$rootScope', '$document', '$compile',
				function($rootScope, $document, $compile) {
					var instance;
					var service = {
		
		
						open: function(options) {
							if(!options.imageList || options.imageList.length <= 0) return false;
		
							if(service.instance){
								service.instance.close();
								service.instance = null;
							}
		
							var setting = {
		
							};
							service.isOpen = true;
							options = options || {};
							angular.extend(setting,options);
							var scope;
		
							//(message.MMStatus==CONF.MSG_SEND_STATUS_SUCC)&&
							scope = $rootScope.$new();
							angular.extend(scope,{
								imageList:options.imageList,
								current:options.current
							});
		
		
							var angularDomEl = angular.element('<div preview-directive class="J_Preview" current="current" image-list="imageList"></div>');
							var domEl = $compile(angularDomEl)(scope);
		
							var body = $document.find('body').eq(0);
							body.append(domEl);
		
		
							var instance = {
								close: function() {
									var elementScope = domEl.scope();
									if(elementScope) elementScope.$destroy();
									domEl.remove();
								}
							};
		
							service.instance = instance;
		
							return instance;
						}
					};
					return service;
				}]
			};
		});
	
	/***/ }),
	/* 323 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('mmlazyDirective',function($timeout) {
			return {
				restrict: 'A',
				link: function(scope, element) {
					var e = "scrollLazyload",
						lazyload = function() {
						$("img.lazy").lazyload({
							"container": element,
							//"effect": "fadeIn",
							"event": e
						});
					};
					lazyload();
		
				}
			};
		})
		.directive('mmlazyWithScrollbarDirective',function($timeout) {
			return {
				restrict: 'A',
				link: function(scope, element) {
					var e = "scrollLazyload",
						lazyload = function() {
							$("img.lazy").lazyload({
								"container": element,
								//"effect": "fadeIn",
								"event": e
							});
						},
						updateCounter = 0,
						lazyloadCounter = 0,
						lazyloadTimer = function (argument) {
							if(updateCounter>1 || lazyloadCounter>20) return;
							console.log('call lazyloadTimer');
							$timeout(function (argument) {
								lazyload();
								lazyloadTimer();
								lazyloadCounter++;
							},(500+lazyloadCounter*200));
						};
		
					var timmer;
		
					scope.$on('onScroll',function(){
						timmer && $timeout.cancel(timmer);
						timmer = $timeout(function (argument) {
							element.trigger(e);
						},200);
					});
					scope.$on('onUpdate',function(){
						updateCounter++;
						lazyload();
					});
		
					lazyloadTimer();
				}
			};
		});
		/**
		 * 重写jqueryScrollbar directive
		 */
		angular.module('jQueryScrollbar', [])
		.directive('jqueryScrollbar', function(){
			return {
				"link": function(scope, element){
					//console.log('jQueryScrollbar init')
					setTimeout(function(){
						element.scrollbar({
							"test":"test",
							"type": "simpble",
							"onScroll":function(y, x){
								scope.$broadcast('onScroll',{y:y,x:x});
		
							},
							"onUpdate":function () {
								//console.log('jqueryScrollbar onUpdate');
								scope.$broadcast('onUpdate',[].slice.call(arguments));
							},
							"onInit":function (argument) {
								//console.log('jqueryScrollbar onInit');
								scope.$broadcast('onInit',[].slice.call(arguments));
							}
						}).on('$destroy', function(){
							element.scrollbar('destroy');
						});
					},0)
				},
				"restring": "AC"
			};
		});
	
	/***/ }),
	/* 324 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*
		 * ngDialog - easy modals and popup windows
		 * http://github.com/likeastore/ngDialog
		 * (c) 2013-2014 MIT License, https://likeastore.com
		 */
		
		(function (root, factory) {
			if (typeof module !== 'undefined' && module.exports) {
				// CommonJS
				module.exports = factory(__webpack_require__(266));
			} else if (true) {
				// AMD
				!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(266)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
			} else {
				// Global Variables
				factory(root.angular);
			}
		}(this, function (angular, undefined) {
			'use strict';
		
			var m = angular.module('ngDialog', []);
		
			var $el = angular.element;
			var isDef = angular.isDefined;
			var style = (document.body || document.documentElement).style;
			var animationEndSupport = isDef(style.animation) || isDef(style.WebkitAnimation) || isDef(style.MozAnimation) || isDef(style.MsAnimation) || isDef(style.OAnimation);
			var animationEndEvent = 'animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend';
			var forceBodyReload = false;
		
			m.provider('ngDialog', function () {
				var defaults = this.defaults = {
					className: 'ngdialog-theme-default',
					plain: false,
					showClose: true,
					closeByDocument: true,
					closeByEscape: true,
					closeByNavigation: false,
					appendTo: false,
					preCloseCallback: false,
					overlay: true,
					cache: true
				};
		
				this.setForceBodyReload = function (_useIt) {
					forceBodyReload = _useIt || false;
				};
		
				this.setDefaults = function (newDefaults) {
					angular.extend(defaults, newDefaults);
				};
		
				var globalID = 0, dialogsCount = 0, closeByDocumentHandler, defers = {};
		
				this.$get = ['$document', '$templateCache', '$compile', '$q', '$http', '$rootScope', '$timeout', '$window', '$controller',
					function ($document, $templateCache, $compile, $q, $http, $rootScope, $timeout, $window, $controller) {
						var $body = $document.find('body');
						if (forceBodyReload) {
							$rootScope.$on('$locationChangeSuccess', function () {
								$body = $document.find('body');
							});
						}
		
						var privateMethods = {
							onDocumentKeydown: function (event) {
								if (event.keyCode === 27) {
									publicMethods.close('$escape');
								}
							},
		
							setBodyPadding: function (width) {
								var originalBodyPadding = parseInt(($body.css('padding-right') || 0), 10);
								$body.css('padding-right', (originalBodyPadding + width) + 'px');
								$body.data('ng-dialog-original-padding', originalBodyPadding);
							},
		
							resetBodyPadding: function () {
								var originalBodyPadding = $body.data('ng-dialog-original-padding');
								if (originalBodyPadding) {
									$body.css('padding-right', originalBodyPadding + 'px');
								} else {
									$body.css('padding-right', '');
								}
							},
		
							performCloseDialog: function ($dialog, value) {
								var id = $dialog.attr('id');
		
								if (typeof $window.Hammer !== 'undefined') {
									var hammerTime = angular.element($dialog).scope().hammerTime;
									hammerTime.off('tap', closeByDocumentHandler);
									hammerTime.destroy && hammerTime.destroy();
									delete $dialog.scope().hammerTime;
								} else {
									$dialog.unbind('click');
								}
		
								if (dialogsCount === 1) {
									$body.unbind('keydown');
								}
		
								if (!$dialog.hasClass("ngdialog-closing")){
									dialogsCount -= 1;
								}
		
								$rootScope.$broadcast('ngDialog.closing', $dialog);
		
								if (animationEndSupport) {
									$dialog.unbind(animationEndEvent).bind(animationEndEvent, function () {
										$dialog.scope().$destroy();
										$dialog.remove();
										if (dialogsCount === 0) {
											$body.removeClass('ngdialog-open');
											privateMethods.resetBodyPadding();
										}
										$rootScope.$broadcast('ngDialog.closed', $dialog);
									}).addClass('ngdialog-closing');
								} else {
									$dialog.scope().$destroy();
									$dialog.remove();
									if (dialogsCount === 0) {
										$body.removeClass('ngdialog-open');
										privateMethods.resetBodyPadding();
									}
									$rootScope.$broadcast('ngDialog.closed', $dialog);
								}
								if (defers[id]) {
									defers[id].resolve({
										id: id,
										value: value,
										$dialog: $dialog,
										remainingDialogs: dialogsCount
									});
									delete defers[id];
								}
							},
		
							closeDialog: function ($dialog, value) {
								var preCloseCallback = $dialog.data('$ngDialogPreCloseCallback');
		
								if (preCloseCallback && angular.isFunction(preCloseCallback)) {
		
									var preCloseCallbackResult = preCloseCallback.call($dialog, value);
		
									if (angular.isObject(preCloseCallbackResult)) {
										if (preCloseCallbackResult.closePromise) {
											preCloseCallbackResult.closePromise.then(function () {
												privateMethods.performCloseDialog($dialog, value);
											});
										} else {
											preCloseCallbackResult.then(function () {
												privateMethods.performCloseDialog($dialog, value);
											}, function () {
												return;
											});
										}
									} else if (preCloseCallbackResult !== false) {
										privateMethods.performCloseDialog($dialog, value);
									}
								} else {
									privateMethods.performCloseDialog($dialog, value);
								}
							}
						};
		
						var publicMethods = {
		
							/*
							 * @param {Object} options:
							 * - template {String} - id of ng-template, url for partial, plain string (if enabled)
							 * - plain {Boolean} - enable plain string templates, default false
							 * - scope {Object}
							 * - controller {String}
							 * - className {String} - dialog theme class
							 * - showClose {Boolean} - show close button, default true
							 * - closeByEscape {Boolean} - default true
							 * - closeByDocument {Boolean} - default true
							 * - preCloseCallback {String|Function} - user supplied function name/function called before closing dialog (if set)
							 *
							 * @return {Object} dialog
							 */
							open: function (opts) {
								var self = this;
								var options = angular.copy(defaults);
		
								opts = opts || {};
								angular.extend(options, opts);
		
								globalID += 1;
		
								self.latestID = 'ngdialog' + globalID;
		
								var defer;
								defers[self.latestID] = defer = $q.defer();
		
								var scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();
								var $dialog, $dialogParent;
		
								$q.when(loadTemplate(options.template || options.templateUrl)).then(function (template) {
		
									$templateCache.put(options.template || options.templateUrl, template);
		
									if (options.showClose) {
										template += '<div class="ngdialog-close"></div>';
									}
		
									self.$result = $dialog = $el('<div id="ngdialog' + globalID + '" class="ngdialog"></div>');
									$dialog.html((options.overlay ?
										'<div class="ngdialog-overlay"></div><div class="ngdialog-content">' + template + '</div>' :
										'<div class="ngdialog-content">' + template + '</div>'));
		
									if (options.data && angular.isString(options.data)) {
										var firstLetter = options.data.replace(/^\s*/, '')[0];
										scope.ngDialogData = (firstLetter === '{' || firstLetter === '[') ? angular.fromJson(options.data) : options.data;
									} else if (options.data && angular.isObject(options.data)) {
										scope.ngDialogData = options.data;
									}
		
									if (options.controller && (angular.isString(options.controller) || angular.isArray(options.controller) || angular.isFunction(options.controller))) {
										var controllerInstance = $controller(options.controller, {
											$scope: scope,
											$element: $dialog
										});
										$dialog.data('$ngDialogControllerController', controllerInstance);
									}
		
									if (options.className) {
										$dialog.addClass(options.className);
									}
		
									if (options.appendTo && angular.isString(options.appendTo)) {
										$dialogParent = angular.element(document.querySelector(options.appendTo));
									} else {
										$dialogParent = $body;
									}
		
									if (options.preCloseCallback) {
										var preCloseCallback;
		
										if (angular.isFunction(options.preCloseCallback)) {
											preCloseCallback = options.preCloseCallback;
										} else if (angular.isString(options.preCloseCallback)) {
											if (scope) {
												if (angular.isFunction(scope[options.preCloseCallback])) {
													preCloseCallback = scope[options.preCloseCallback];
												} else if (scope.$parent && angular.isFunction(scope.$parent[options.preCloseCallback])) {
													preCloseCallback = scope.$parent[options.preCloseCallback];
												} else if ($rootScope && angular.isFunction($rootScope[options.preCloseCallback])) {
													preCloseCallback = $rootScope[options.preCloseCallback];
												}
											}
										}
		
										if (preCloseCallback) {
											$dialog.data('$ngDialogPreCloseCallback', preCloseCallback);
										}
									}
		
									scope.closeThisDialog = function (value) {
										privateMethods.closeDialog($dialog, value);
									};
		
									$timeout(function () {
										$compile($dialog)(scope);
		
										var widthDiffs = $window.innerWidth - $body.prop('clientWidth');
										$body.addClass('ngdialog-open');
										var scrollBarWidth = widthDiffs - ($window.innerWidth - $body.prop('clientWidth'));
										if (scrollBarWidth > 0) {
											privateMethods.setBodyPadding(scrollBarWidth);
										}
										$dialogParent.append($dialog);
		
										if (options.name) {
											$rootScope.$broadcast('ngDialog.opened', {dialog: $dialog, name: options.name});
										} else {
											$rootScope.$broadcast('ngDialog.opened', $dialog);
										}
									});
		
									if (options.closeByEscape) {
										$body.bind('keydown', privateMethods.onDocumentKeydown);
									}
		
									if (options.closeByNavigation) {
										$rootScope.$on('$locationChangeSuccess', function () {
											privateMethods.closeDialog($dialog);
										});
									}
		
									closeByDocumentHandler = function (event) {
										var isOverlay = options.closeByDocument ? $el(event.target).hasClass('ngdialog-overlay') : false;
										var isCloseBtn = $el(event.target).hasClass('ngdialog-close');
		
										if (isOverlay || isCloseBtn) {
											publicMethods.close($dialog.attr('id'), isCloseBtn ? '$closeButton' : '$document');
										}
									};
		
									if (typeof $window.Hammer !== 'undefined') {
										var hammerTime = scope.hammerTime = $window.Hammer($dialog[0]);
										hammerTime.on('tap', closeByDocumentHandler);
									} else {
										$dialog.bind('click', closeByDocumentHandler);
									}
		
									dialogsCount += 1;
		
									return publicMethods;
								});
		
								return {
									id: 'ngdialog' + globalID,
									closePromise: defer.promise,
									close: function (value) {
										privateMethods.closeDialog($dialog, value);
									}
								};
		
								function loadTemplateUrl (tmpl, config) {
									return $http.get(tmpl, (config || {})).then(function(res) {
										return res.data || '';
									});
								}
		
								function loadTemplate (tmpl) {
									if (!tmpl) {
										return 'Empty template';
									}
		
									if (angular.isString(tmpl) && options.plain) {
										return tmpl;
									}
		
									if (typeof options.cache === 'boolean' && !options.cache) {
										return loadTemplateUrl(tmpl, {cache: false});
									}
		
									return $templateCache.get(tmpl) || loadTemplateUrl(tmpl, {cache: true});
								}
							},
		
							/*
							 * @param {Object} options:
							 * - template {String} - id of ng-template, url for partial, plain string (if enabled)
							 * - plain {Boolean} - enable plain string templates, default false
							 * - name {String}
							 * - scope {Object}
							 * - controller {String}
							 * - className {String} - dialog theme class
							 * - showClose {Boolean} - show close button, default true
							 * - closeByEscape {Boolean} - default false
							 * - closeByDocument {Boolean} - default false
							 * - preCloseCallback {String|Function} - user supplied function name/function called before closing dialog (if set); not called on confirm
							 *
							 * @return {Object} dialog
							 */
							openConfirm: function (opts) {
								var defer = $q.defer();
		
								var options = {
									closeByEscape: false,
									closeByDocument: false
								};
								angular.extend(options, opts);
		
								options.scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();
								options.scope.confirm = function (value) {
									defer.resolve(value);
									var $dialog = $el(document.getElementById(openResult.id));
									privateMethods.performCloseDialog($dialog, value);
								};
		
								var openResult = publicMethods.open(options);
								openResult.closePromise.then(function (data) {
									if (data) {
										return defer.reject(data.value);
									}
									return defer.reject();
								});
		
								return defer.promise;
							},
		
							/*
							 * @param {String} id
							 * @return {Object} dialog
							 */
							close: function (id, value) {
								var $dialog = $el(document.getElementById(id));
		
								if ($dialog.length) {
									privateMethods.closeDialog($dialog, value);
								} else {
									publicMethods.closeAll(value);
								}
		
								return publicMethods;
							},
		
							closeAll: function (value) {
								var $all = document.querySelectorAll('.ngdialog');
		
								angular.forEach($all, function (dialog) {
									privateMethods.closeDialog($el(dialog), value);
								});
							},
		
							getDefaults: function () {
								return defaults;
							}
						};
		
						return publicMethods;
					}];
			});
		
			m.directive('ngDialog', ['ngDialog', function (ngDialog) {
				return {
					restrict: 'A',
					scope : {
						ngDialogScope : '='
					},
					link: function (scope, elem, attrs) {
						elem.on('click', function (e) {
							e.preventDefault();
		
							var ngDialogScope = angular.isDefined(scope.ngDialogScope) ? scope.ngDialogScope : 'noScope';
							angular.isDefined(attrs.ngDialogClosePrevious) && ngDialog.close(attrs.ngDialogClosePrevious);
		
							var defaults = ngDialog.getDefaults();
		
							ngDialog.open({
								template: attrs.ngDialog,
								className: attrs.ngDialogClass || defaults.className,
								controller: attrs.ngDialogController,
								scope: ngDialogScope,
								data: attrs.ngDialogData,
								showClose: attrs.ngDialogShowClose === 'false' ? false : (attrs.ngDialogShowClose === 'true' ? true : defaults.showClose),
								closeByDocument: attrs.ngDialogCloseByDocument === 'false' ? false : (attrs.ngDialogCloseByDocument === 'true' ? true : defaults.closeByDocument),
								closeByEscape: attrs.ngDialogCloseByEscape === 'false' ? false : (attrs.ngDialogCloseByEscape === 'true' ? true : defaults.closeByEscape),
								preCloseCallback: attrs.ngDialogPreCloseCallback || defaults.preCloseCallback
							});
						});
					}
				};
			}]);
		}));
	
	/***/ }),
	/* 325 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('mmRepeat', ['$document','$compile','$rootScope',function( $document,$compile,$rootScope) {
		
		
				/**
				 * 根据当前情况，计算 Y轴 位移之后须显示到的目标项
				 * @param list
				 * @param startIndex
				 * @param startY
				 * @param endY
				 * @param heightCalc
				 * @returns {*}
				 */
				function getShowArae(list,startIndex,startY,endY,heightCalc){
					var item , total = 0,prevTotal ;
					if(list.length === 0) return 0;
		
					if(startY > endY){
						for(var i = startIndex;i>-1;i--){
							item = list[i];
							prevTotal = total;
							total += (item._h ||  (item._h = heightCalc(item)));
							if(startY - total < endY){
								return {index:i,total: prevTotal};
							}
						}
						return {index:0,total: 0};
					}else{
						for(var i = startIndex;i < list.length;i++){
							item = list[i];
							prevTotal = total;
							total += (item._h ||  (item._h = heightCalc(item)));
							if(startY + total > endY){
								return {index:i,total: prevTotal};
							}
						}
						return {index:list.length - 1,total: total};
					}
		
				}
		
				/**
				 * 获取一部分item的高度总和
				 * @param list
				 * @param start
				 * @param end
				 * @param heightCalc
				 * @returns {number}
				 */
				function getTotalHeight(list,start,end,heightCalc){
					if(list.length === 0 || start === end) return 0;
		
					var item,total=0 ;
					for(var i = start;i<end;i++){
						item = list[i];
						total += (item._h ||  (item._h = heightCalc(item)));
					}
					return total;
				}
		
		
				function getRenderData(list,scrollDataY,bufferHeight,heightCalc){
		
					var startIndex,endIndex,topHeight,bottomHeight,showAraeResult;
					var startY = scrollDataY.scroll - bufferHeight;
					var endY = scrollDataY.scroll + scrollDataY.visible + bufferHeight;
		
					if (startY > 0) {
						showAraeResult= getShowArae(list, 0, 0, startY, heightCalc);
						startIndex = showAraeResult.index;
						startY = showAraeResult.total;
					} else {
						startIndex = 0;
						startY = 0;
					}
		
					endIndex = getShowArae(list, startIndex, startY, endY, heightCalc).index;
					endIndex = endIndex >= list.length ? (list.length - 1) : endIndex;
		
					topHeight = getTotalHeight(list, 0, startIndex, heightCalc);
					bottomHeight = getTotalHeight(list, endIndex + 1, list.length, heightCalc);
		
		
		
					return {
						topHeight:topHeight,
						bottomHeight:bottomHeight,
						startIndex:startIndex,
						endIndex:endIndex
					}
		
				}
		
		
				function render(scope,scrollDataY,currentList,list){
					var renderList;
					var renderData = getRenderData(list,scrollDataY,scope.bufferHeight,scope.heightCalc);
					scope.bottomHeight = renderData.bottomHeight;
					scope.topHeight = renderData.topHeight;
					currentList.length = 0;
					renderList = list.slice(renderData.startIndex, renderData.endIndex + 1);
		
		
					[].push.apply(currentList, renderList);
		
		
	// 	            console.timeEnd('render');
				}
		
				function addOffset(list){
					if(list.length<= 0 ) return;
					var item;
					var offsetTop = 0;
					for(var i = 0;i<list.length;i++){
						item = list[i];
						item._offsetTop = offsetTop;
						offsetTop += item._h;
					}
				}
		
				function calc(list,heightCalc,noCache){
					if(list.length<= 0 ) return;
					var item;
		
					for(var i = 0;i<list.length;i++){
						item = list[i];
						if(!item._h || noCache) item._h = heightCalc(item);
					}
				}
		
				function preCalc(list,heightCalc,cb){
					var newcb=function(list){
						setTimeout(function(){
		
							cb(list);
						},0)
					};
		
		
					if(list.length == 0 ) {
						cb(list);
						return;
					}
		
					var len = list.length;
					var flag = 0,item;
					for(var i = 0 ; i < len;i++){
						item = list[i];
						if(item._h){
							flag++;
							if(flag == len ){
								newcb(list);
							}
						}else{
							console.log('pre','callcalc')
						   /* if(!item._calcing){
								item._calcing = true;*/
								heightCalc(item,(function(item){
									return  function(height){
										item._h = height;
										item._calcing = false;
										flag++;
										console.log('pre',item,flag);
										// 接受消息，在当前窗口时  MK
										console.log("发送方账号: " + item.FromUserName)
										console.log("名字+内容: "+item.MMDigest)
										console.log("内容：" + item.MMActualContent)
										getMsg(item);
										if(flag == len ){
											newcb(list);
										}
									}
								})(item));
						  /*  }*/
		
						}
		
					}
				}
		
				function alreadyCalc(list){
					var result = true;
					for(var i =0;i<list.length;i++){
						if(!list[i]._h){
							result = false;
						}
					}
					return result;
				}
		
		
		
		
				/**
				 * 组件参数：
				 * heightCalc（item）(function): item 为数据计算， heightCalc 应该返回该数据项对应的列表项的高度
				 * bufferHeight（number）: mmrepeater 为可视区域外预留的缓冲区，缓冲区的元素同样会被加载
				 * preCalc (bool): mmrepeater 是否在渲染节点前先计算节点的高度，支持异步
				 */
				return {
					restrict: 'EA',
					priority:1000,
					scope:true,/*{
						heightCalc:"=",
						bufferHeight:"="
					},*/
					terminal: true,
					link: function (scope, element, attributes) {
		
							var selectedItems = [];
							var list =  [];
							var scrollDataY = {
								maxScroll: 0,
								scroll: 0,
								size: 0,
								visible: 687
							};
							var onSelectedChangeHandler;
		
		
							var match = attributes.mmRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
							// match[2] 是 item in XXX 中的 XXX
							var listKey = match[2];
							var itemKey = match[1];
		
							var angularDomEl = '<div ng-style="{height:topHeight}" class="top-placeholder"></div><div ng-repeat="'+attributes.mmRepeat+'">'+element.html()+'</div><div ng-style="{height:bottomHeight}" class="bottom-placeholder"></div>';
							var domEl = $compile(angularDomEl)(scope);
		
							element.html('');
							element.append(domEl);
		
							if(!scope.bufferHeight) {
								scope.bufferHeight = 100;
							}
		
							if(!attributes.preCalc || attributes.preCalc === 'false'){
								scope.preCalc = false;
							}else{
								scope.preCalc = true;
							}
		
		
		
		
							scope[listKey] = [];
							scope.$on('onScroll',function(e,scrollData){
								scrollDataY = scrollData.y;
		
								if(scope.heightCalc && scope.heightCalc.length === 2){
									 if(!alreadyCalc(list)){
		
										 preCalc(list,scope.heightCalc,function(){
											 if(!alreadyCalc(list)){
												 return;
											 }
											 addOffset(list);
											 render(scope,scrollDataY,scope[listKey],list);
											 scope.$digest();
											 scope.$emit('mmRepeat:reCalc');
										 });
										 return;
									 }
								}
		
								//if(element.offset().left>100 && element.children().length > 6) {alert( JSON.stringify(scrollData)); }
								//console.log('scroll',scrollData);
								render(scope,scrollDataY,scope[listKey],list);
								scope.$digest();
							});
		
		
		
		
							scope.$parent.$watch(attributes.heightCalc, function (value) {
								if(typeof  value === 'function'){
									scope.heightCalc = value;
								}
							});
							if(attributes.height){
								scope.heightCalc = function(){
									return parseInt(attributes.height);
								}
							}
		
							scope.bufferHeight = parseInt(attributes.bufferHeight)
							scope.$parent.$watchCollection(match[2], function (collection) {
		
								if (!(collection  instanceof Array)){
									return;
								}
		
								list = collection;
								if (collection.length > 0) {
									// 因为回收了大部分不可区域的项，所以要有一个 _index 来指明该项的位置
									for(var i = 0;i<list.length;i++){
										list[i]._index = i;
									}
		
	// 	                            console.time('calc');
									if(scope.preCalc){
										preCalc(list,scope.heightCalc,function(){
											console.timeEnd('calc');
											console.time('render')
											if(!alreadyCalc(list)){
												return;
											}
											addOffset(list);
											render(scope,scrollDataY,scope[listKey],list);
											scope.$digest();
											scope.$emit('mmRepeat:change');
		
		
										});
									}else{
										calc(list,scope.heightCalc,attributes.noCache);
										addOffset(list);
		
										render(scope,scrollDataY,scope[listKey],list);
										scope.$emit('mmRepeat:change');
		
		
									}
		
		
								}else{
									scope[listKey].length = 0;
									scope.$emit('mmRepeat:change');
		
		
								}
							})
						}
				};
			}])
	
	/***/ }),
	/* 326 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('mmRepeatKeyboard', ['$timeout', 'utilFactory','confFactory', function ($timeout, utilFactory,confFactory) {
		
				return {
					restrict: 'A',
					priority: 1001,
					scope:false,
					link: function (scope, element, attrs) {
		
						var match = attrs.mmRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
						var listKey = match[2];
		
						scope.$parent.$watch(listKey,function(value){
							if(value) list = value;
						})
		
						var list = scope.$parent[listKey]
						var scrollSelector = attrs.mmRepeatKeyboardScrollSelector;
		
						var scrollContainer = $(scrollSelector)[0];
						if (!scrollContainer) {
							console.error('scrollContainer 不存在');
							return;
						}
		
						var currentItem;
						var judgeFunMap = {};
						scope.$parent.mmRepeatKeyboard = {
							started:false,
							start: function () {
								if(!this.started){
									$(document).on('keydown', 'body', navKeydown);
									this.started = true;
								}
		
							},
							stop: function () {
		
								this.started = false;
								$(document).off('keydown', 'body', navKeydown);
							},
							setJudgeFun: function (fun, key) {
								if (key) {
									judgeFunMap[key] = fun;
								} else {
									judgeFunMap['default'] = fun;
								}
							},
							setSelectItem:function(item){
								currentItem = item;
							}
						};
		
						function selectItem(item) {
							scope.$emit('mmrepeat:select', item);
						};
		
		
						function showContact(container,item,lastSelectable){
							var itemHeigth = item._h;
							var offsetTop = item._offsetTop;
							var scrollTop = container.scrollTop;
		
							if(scrollTop >= offsetTop){
								container.scrollTop = offsetTop;
								if(lastSelectable) container.scrollTop = 0;
								return;
							}
		
							var BottomLimit = offsetTop + itemHeigth  - container.clientHeight;
							if(scrollTop < BottomLimit){
								container.scrollTop = BottomLimit;
							}
						}
		
		
		
						function navKeydown(e) {
							if(!list) return;
							var lastSelectable=false;
							var judgeFun;
							if (e.ctrlKey) {
								judgeFun = judgeFunMap['ctrl'] || judgeFunMap['default'];
		
							} else {
								judgeFun = judgeFunMap['default'];
							}
		
							if (!judgeFun) {
								judgeFun = function(){return true};
		
							}
		
		
							if(!currentItem){
								currentItem =  list[0];
								if(!currentItem) return;
		
								if(judgeFun(currentItem)){
									selectItem(currentItem);
									return;
								}
							}
		
							if (!currentItem) return;
		
							var nextItem = currentItem;
		
								if (nextItem) {
									switch (e.keyCode) {
										case confFactory.KEYCODE_ARROW_UP:
											do {
												nextItem  = (nextItem._index - 1 < 0 )?currentItem: list[nextItem._index - 1];
											} while (!judgeFun(nextItem))
											if(nextItem == currentItem){
												lastSelectable = true;
											}
											break;
										case confFactory.KEYCODE_ARROW_DOWN:
											do {
												nextItem = (nextItem._index + 1 >= list.length) ? currentItem : list[nextItem._index + 1];
											} while (!judgeFun(nextItem))
											break;
										default :
											return;
									}
		
		
		
									//if(currentItem != nextItem){
									   /* utilFactory.fitRun('navKeydown', function () {
											selectItem(nextItem);
											*//*                      scope.showProfile(nextItem);
											 $rootScope.$digest();*//*
										}, 200, 800)*/
										currentItem = nextItem;
										utilFactory.wait(function () {
											return typeof currentItem._offsetTop != 'undefined';
										}, function () {
											showContact(scrollContainer,nextItem,lastSelectable);
											selectItem(nextItem);
		
										}, 10);
		
								   // }
		
		
		
								}
		
		
								/*$rootScope.$digest();
								showContact($(scrollBodySelector)[0], nextItem);*/
		
		
						  /*  utilFactory.wait(function () {
								return typeof currentItem._offsetTop != 'undefined';
							}, function () {
		
		
							}, 10);*/
		
		
							if (e.keyCode == confFactory.KEYCODE_ARROW_UP || e.keyCode == confFactory.KEYCODE_ARROW_DOWN) {
								e.preventDefault();
							}
		
		
						}
		
						scope.$on('$destroy',function(){
							$(document).off('keydown', 'body', navKeydown);
						})
		
					}
				};
			}])
	
	/***/ }),
	/* 327 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
		.directive('searchListDirective', [function () {
			return {
				restrict: 'A',
				link: function(scope, element){
					var HEADER_HEIGHT = 30,
						ITEM_HEIGTH = 66;
					var allContacts = scope.allContacts, ele = element[0],
						minIndex = allContacts.length && allContacts[0].type && allContacts[0].type == "header" ? 1 : 0,
						maxIndex = allContacts.length - 1;
					scope.selectIndex = minIndex;
		
					function showContact(selectIndex){
						var item = allContacts[selectIndex];
						if(!item) return ;
		
						var itemHeigth = item._h;
						var offsetTop = item._offsetTop;
						var scrollTop = ele.scrollTop;
						if(scrollTop > offsetTop ||typeof item.NickName === 'undefined'){
							if(item._index == 1){
								ele.scrollTop = 0;
							}else{
								ele.scrollTop = offsetTop;
							}
		
							return;
						}
		
						// 用 clientHeight 是为了去掉 IE 下滚动条高度的影响
						var BottomLimit = offsetTop + itemHeigth  - ele.clientHeight;
						if(scrollTop < BottomLimit){
							ele.scrollTop = BottomLimit;
						}
					}
		
					scope.$on("root:searchList:keyArrowUp", function () {
		
						var index = scope.selectIndex;
						do {
							--index;
						} while (index > minIndex && allContacts[index].type == "header");
		
						index = index < minIndex ? minIndex : index;
						scope.selectIndex = index;
						showContact(index);
					});
					scope.$on("root:searchList:keyArrowDown", function () {
						var maxIndex = allContacts.length-1;
						var index = scope.selectIndex;
						do {
							++index;
						} while (index < maxIndex && allContacts[index].type == "header");
		
						index = index > maxIndex ? maxIndex : index;
						scope.selectIndex = index;
						showContact(index);
					});
					scope.$on("root:searchList:keyEnter", function () {
						scope.clickUserCallback(allContacts[scope.selectIndex]);
					});
				}
			}
		}]);
	
	/***/ }),
	/* 328 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('navChatDirective', [
				'$timeout',
				'$log',
				'$document',
				'$stateParams',
				'$rootScope',
				'chatFactory',
				'accountFactory',
				'contactFactory',
				'appFactory',
				'confFactory',
				'utilFactory',
				'stateManageService',
				function($timeout,$log,$document,$stateParams, $rootScope,chatFactory, accountFactory, contactFactory, appFactory, confFactory, utilFactory,stateManageService) {
		
		
		
				return {
					restrict: 'EA',
					scope:true,
		
					templateUrl:'navChat.html',
					link: function (scope, element, attributes) {
		
						stateManageService.on('navChat:active',function navChatStateChange(value){
							if(value){
								$(document).on('keydown','body',navKeydown);
		
							}else{
								$(document).off('keydown','body',navKeydown);
		
							}
						});
						function navKeydown(e){
		
							var list= scope.chatList,item,nextItem;
							if(!stateManageService.canDo('navKeydown')) return;
							if(!scope.currentUserName) {
								var first;
								if((e.keyCode == confFactory.KEYCODE_ARROW_UP || e.keyCode == confFactory.KEYCODE_ARROW_DOWN) && (first = list[0]) ){
									scope.currentUserName = first.UserName;
		
									chatFactory.setCurrentUserName(first.UserName);
									scope.showChatContentByUserName(first.UserName);
									$rootScope.$digest();
									showContact($('.chat_list.scroll-content')[0],first);
								}else{
									return;
								}
							}else{
								item = getItemByUserName(list,scope.currentUserName);
								nextItem = item;
								utilFactory.wait(function(){
									return typeof item._offsetTop != 'undefined';
								},function(){
		
									switch(e.keyCode){
										case confFactory.KEYCODE_ARROW_UP:
											nextItem = (item._index - 1 < 0) ? item : list[item._index - 1];
											break;
										case confFactory.KEYCODE_ARROW_DOWN:
											nextItem = (item._index + 1>= list.length) ? item : list[item._index + 1];
											break;
										default :
											return;
									}
		
		
									utilFactory.fitRun('navKeydown',function(){
										chatFactory.setCurrentUserName(nextItem.UserName);
										$rootScope.$digest();
									},200,800)
									scope.showChatContentByUserName(nextItem.UserName);
									$rootScope.$digest();
									showContact($('.chat_list.scroll-content')[0],nextItem);
		
								},10);
							}
		
		
		
		
		
							if(e.keyCode ==  confFactory.KEYCODE_ARROW_UP || e.keyCode ==  confFactory.KEYCODE_ARROW_DOWN){
								e.preventDefault();
							}
		
		
						}
		
		
		
						$timeout(function(){
		
							scope.chatList = chatFactory.getChatList();
							scope.currentUserName = chatFactory.getCurrentUserName();
		
							// 挫逼实现watch contacts更新来更新chatList
							scope.$watch(function () {
								return contactFactory.contactChangeFlag;
							},function (newValue) {
		
								//update chatlist
								chatFactory.getChatList();
							});
						},0);
		
						$rootScope.$on('contact:settop',function(){
							chatFactory.getChatList();
						});
						function getItemByUserName(list,userName){
							var item;
							for(var i = 0;i<list.length;i++){
								item = list[i];
								if(item.UserName === userName){
									return item;
								}
							}
						}
		
		
						function showContact(container,item){
							var itemHeigth = item._h;
							var offsetTop = item._offsetTop;
							var scrollTop = container.scrollTop;
		
							if(scrollTop > offsetTop){
								container.scrollTop = offsetTop;
								return;
							}
		
							var BottomLimit = offsetTop + itemHeigth  - container.clientHeight;
							if(scrollTop < BottomLimit){
								container.scrollTop = BottomLimit;
							}
						}
		
		
		
		
		
		
						scope.$watch(function(){
							return chatFactory.getCurrentUserName();
						},function(value){
							if(value){
								scope.showChatContentByUserName(value);
								contactFactory.addBatchgetChatroomMembersContact(value);
							}
						})
		
						/**
						 * 点击聊天列表项，显示对应的聊天内容
						 * @param  {string} userName
						 * @param  {[type]} $index
						 */
						scope.showChatContentByUserName = function (userName) {
							console.log('setusername',userName);
						   // chatFactory.setCurrentUserName(userName);
							scope.currentUserName = userName;
		
							//update chatlist
							chatFactory.getChatList();
		
						};
		
						scope.itemClick = function(userName){
							chatFactory.setCurrentUserName(userName);
							scope.showChatContentByUserName(userName);
						};
		
		
						scope.$on('root:notification:click', function(e, username){
							scope.$apply(function(){
								chatFactory.setCurrentUserName(username);
								scope.showChatContentByUserName(username);
							});
						});
		
						scope.$on('root:statechange',function(e){
							setTimeout(function(){
								$('.chat_list.scroll-content')[0].scrollTop = 0;
							},0)
		
		
						});
		
						scope.$on('app:chat:dblclick',function (e) {
						   // alert('dblclick');
						});
		
						scope.$on('root:deleteChat', function (e,userName) {
							chatFactory.deleteChatList(userName);
							chatFactory.deleteChatMessage(userName);
							if(chatFactory.getCurrentUserName()==userName){
								chatFactory.setCurrentUserName('');
							}
						});
		
						scope.$on('root:msgSend:success', function(e, msg){
							var to = msg.ToUserName;
							angular.forEach(scope.chatList, function(item, index){
								if(item.UserName === to){
									item.MMStatus = msg.MMStatus;
									if(!scope.$$phase) scope.$digest();
									return;
								}
							});
						});
						scope.$on('$destroy',function(){
							stateManageService.change('navChat:active',false);
						});
		
					}
				};
			}]);
	
	/***/ }),
	/* 329 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('navContactDirective',  [
				'$rootScope',
				'$timeout',
				'$state',
				'contactFactory',
				'stateManageService',
				'confFactory',
				'utilFactory',
				function($rootScope, $timeout,$state, contactFactory,stateManageService,confFactory,utilFactory) {
		
		
		
				return {
					restrict: 'EA',
					scope:true,
		
					templateUrl: 'navContact.html',
					link: function (scope, element, attributes) {
						var scrollBodySelector = '#navContact.J_ContactScrollBody';
						stateManageService.on('navContact:active',function navContactStateChange(value){
							if(value){
								$(document).on('keydown','body',navKeydown);
							}else{
								$(document).off('keydown','body',navKeydown);
		
							}
		
						});
						function navKeydown(e){
							//if(!scope.currentContact) return;
							if(!stateManageService.canDo('navKeydown')) return;
							var list= scope.allContacts;
							var item = scope.currentContact || list[0];//getItemByUserName(list,scope.currentContact);
							var nextItem = item;
		
							utilFactory.wait(function(){
								return typeof item._offsetTop != 'undefined';
							},function(){
								if(item){
									if(!e.ctrlKey){
										switch(e.keyCode){
											case confFactory.KEYCODE_ARROW_UP:
												do{
													if(nextItem._index - 1 < 0){
														// 回溯机制
														for(var i = nextItem._index+1;i<list.length;i++){
															nextItem = list[i];
															if(typeof nextItem.NickName !== 'undefined') break;
		
														}
		
														// 回溯失败直接跳出
														break;
													}else{
														nextItem = list[nextItem._index - 1];
													}
		
												}while(typeof nextItem.NickName === 'undefined')
		
												break;
											case confFactory.KEYCODE_ARROW_DOWN:
												do{
													nextItem = (nextItem._index + 1>= list.length) ? item : list[nextItem._index + 1];
												}while(typeof nextItem.NickName === 'undefined')
												break;
											default :return;
										}
										utilFactory.fitRun('navKeydown',function(){
											scope.showProfile(nextItem);
											$rootScope.$digest();
										},200,800)
		
										scope.currentContact = nextItem;
									}else{
										switch(e.keyCode){
											case confFactory.KEYCODE_ARROW_UP:
												do{
													nextItem = (nextItem._index - 1 < 0) ? item : list[nextItem._index - 1];
												}while(typeof nextItem.NickName !== 'undefined');
		
												break;
											case confFactory.KEYCODE_ARROW_DOWN:
												do{
		
		
													if(nextItem._index + 1>= list.length){
														for(var i = nextItem._index-1;i>=0;i--){
															nextItem = list[i];
															if(typeof nextItem.NickName === 'undefined') break;
		
														}
		
														// 一般情况下回溯能找到想要的那个 head ，如果找不到，就是异常情况，直接跳出
														break;
													}else{
														nextItem = list[nextItem._index + 1];
													}
		
												}while(typeof nextItem.NickName !== 'undefined')
												break;
											default :return;
										}
										scope.currentContact = nextItem;
									}
		
								}
		
		
		
								$rootScope.$digest();
								showContact($(scrollBodySelector)[0],nextItem);
		
							},10);
		
		
							if(e.keyCode ==  confFactory.KEYCODE_ARROW_UP || e.keyCode ==  confFactory.KEYCODE_ARROW_DOWN){
								e.preventDefault();
							}
		
		
						}
		
		
		
		
		
		
						scope.dblclick=function(contact){
							$state.go('chat',{userName:contact.UserName});
						}
		
						function showContact(container,item){
							var itemHeigth = item._h;
							var offsetTop = item._offsetTop;
							var scrollTop = container.scrollTop;
							if(scrollTop > offsetTop ||typeof item.NickName === 'undefined'){
								if(item._index == 1){
									container.scrollTop = 0;
								}else{
									container.scrollTop = offsetTop;
								}
		
								return;
							}
		
							var BottomLimit = offsetTop + itemHeigth  - container.clientHeight;
							if(scrollTop < BottomLimit){
								container.scrollTop = BottomLimit;
							}
						}
						/**
						 * 更新contacts
						 */
						function updateContacts (argument) {
						   // console.time("showContacts");
							scope.currentContact = contactFactory.getCurrentContact();
		
							scope.allContacts = contactFactory.pickContacts(['star','chatroom','friend'],{
								friend:{
									isWithoutStar:true,
									isWithoutBrand:true
								},
								chatroom: {isSaved: true}
							}).result;
		
							// console.timeEnd("showContacts");
							//lazyloadImages();
						}
		
						$timeout(function(){
							scope.$watch(function () {
								return contactFactory.contactChangeFlag;
							},function (newValue,oldValue) {
								updateContacts();
							});
		
							scope.showProfile = function (contact) {
								contactFactory.setCurrentContact(contact);
								scope.currentContact = contactFactory.getCurrentContact();
							}
						},0);
		
		
					}
				};
			}])
	
	/***/ }),
	/* 330 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('navReadDirective', [
				'$timeout',
				'$log',
				'$document',
				'$stateParams',
				'$rootScope',
				'$state',
				'chatFactory',
				'accountFactory',
				'contactFactory',
				'appFactory',
				'confFactory',
				'utilFactory',
				'stateManageService',
				'subscribeMsgService',
		
				function ($timeout, $log, $document, $stateParams, $rootScope,$state, chatFactory, accountFactory, contactFactory, appFactory, confFactory, utilFactory, stateManageService, subscribeMsgService) {
		
		
					function format(subscribeMsgs){
						var result  = [],item;
						for(var i = 0;i<subscribeMsgs.length;i++){
							item = subscribeMsgs[i];
							result.push(item);
							[].push.apply(result,item.MPArticleList);
						}
						return result;
					}
		
					return {
						restrict: 'EA',
						scope: true,
						templateUrl: 'navRead.html',
						link: function (scope, element, attributes) {
							scope.subscribeMsgs = [];
							scope.articleList = [];
							// 初始化完成之后 ，[] 会被替换成 subscribeMsgService 里面的对象，defaultValue 会消失，代表该列表已经不是默认列表
							// 用来识别初始化完成之后为 空数组 和初始化完成前就是 空数组 两种情况
							scope.subscribeMsgs.defaultValue = true;
							scope.$watch(function () {
								return subscribeMsgService.changeFlag;
							}, function (newValue) {
								if(newValue==0){
									return;
								}
								scope.subscribeMsgs = subscribeMsgService.getSubscribeMsgs();
								scope.articleList = format(scope.subscribeMsgs);
		
								if(!scope.currentItem && scope.subscribeMsgs.length > 0){
									subscribeMsgService.current =scope.currentItem = scope.subscribeMsgs[0].MPArticleList[0];
		
									scope.mmRepeatKeyboard.setSelectItem(scope.currentItem);
								}
							});
		
							scope.mmRepeatKeyboard.setJudgeFun(function(item){
								return !item.UserName;
							})
							stateManageService.on('dialog:open',function (value){
								if(value){
									scope.mmRepeatKeyboard.stop();
		
									// $(document).on('keydown','body',keydown);
		
								}else{
									scope.mmRepeatKeyboard.start();
									//  $(document).off('keydown','body',keydown);
								}
							});
							stateManageService.on('navRead:active',function navChatStateChange(value){
		
								if(value){
									scope.mmRepeatKeyboard.start();
								   // $(document).on('keydown','body',keydown);
		
								}else{
									scope.mmRepeatKeyboard.stop();
								  //  $(document).off('keydown','body',keydown);
								}
							});
		
		
						   /* var navActive = true;
							function keydown(e){
								switch (e.keyCode) {
									case confFactory.KEYCODE_ARROW_LEFT:
										scope.mmRepeatKeyboard.start();
										navActive = true;
										break;
									case confFactory.KEYCODE_ARROW_RIGHT:
										scope.mmRepeatKeyboard.stop();
										$('.reader .iframe')[0].contentWindow.focus()
										navActive = false;
		
									   *//* $('#navView').focus();*//*
										break;
		
								}
		*//* *//*
								if ((e.keyCode == confFactory.KEYCODE_ARROW_UP || e.keyCode == confFactory.KEYCODE_ARROW_DOWN)&&!navActive) {
								  //  $('.reader .iframe').focus();
									*//*setTimeout(function(){
										$('.reader .iframe').blur();
									},100);*//*
								}
		
		
		
								if (e.keyCode == confFactory.KEYCODE_ARROW_LEFT || e.keyCode == confFactory.KEYCODE_ARROW_RIGHT) {
									e.preventDefault();
								}
							}
		*/
		
							scope.heightCalc  =function(item){
								if(item.UserName){
									if(item._index == 0){
										return 45;
									}else{
										return 55;
									}
								}else{
									return 60;
								}
		
							};
		
							scope.$on('mmrepeat:select',function(e,item){
								utilFactory.fitRun('navKeydown', function () {
		
									$state.go('read',{readItem:item});
		
								}, 200, 1400);
								subscribeMsgService.current = scope.currentItem = item;
		
								console.log('select',item);
							});
		
		
		
							scope.itemClick=function(item){
								subscribeMsgService.current = scope.currentItem = item;
								scope.mmRepeatKeyboard.setSelectItem(item);
								$state.go('read',{readItem:item});
							};
		
							/* scope.$on('$destroy',function(){
							 stateManageService.change('navChat:active',false);
							 })*/
						}
					};
				}]);
	
	/***/ }),
	/* 331 */
	/***/ (function(module, exports) {
	
		/**
		 * Created by arminchen on 2015/3/25.
		 * demo: <img class="qrcode" mm-src="{{qrcodeUrl}}"  mm-src-parallel mm-src-timeout="2000" mm-src-retry-count="10" src="images/qrcode.jpg">
		 */
		angular.module('Directives')
			.directive('mmSrc', ['$document','$timeout','$rootScope',function( $document,$timeout,$rootScope) {
		
				return {
					priority: 99,
					link: function(scope, element, attr) {
						var name = 'src';
						var defaultSrc = attr.src;
						var retryTimeout = attr.mmSrcTimeout ?parseInt(attr.mmSrcTimeout) : 5000;
						var retryCount = attr.mmSrcRetryCount?parseInt(attr.mmSrcRetryCount):4;
						var parallel = typeof attr.mmSrcParallel != 'undefined';
						var node = element[0];
						var count = 0 ;
						var srcValue ,loaded=false;
						var srcTmp;
						var imgTmpList = [];
						var timeoutList = [];
						var failCount = 0;
						var onloadKey = attr.mmSrcLoad;
						var onerrorKey = attr.mmSrcError;
						attr.$observe('mmSrc', function(value) {
							if(value){
								srcValue = value;
								load();
							}
						});
		
						function clearImgTmp(){
							var img;
							while(img = imgTmpList.pop()){
								delete img.src;
								img.onload = null;
								img.onerror = null;
							}
		
							if(onloadKey&&scope[onloadKey]) scope[onloadKey].call(element);
						}
		
						function fail(e){
		
							node.onerror = null;
							node.onload = null;
							if(!retry()){
								console.log(e);
								// 可能会触发多次
								attr.$set(name, defaultSrc);
							   if(onerrorKey&&scope[onerrorKey]) scope[onerrorKey].call(element);
							}
						}
		
						function load(){
							loaded = false;
		
							node.onload = function(){
								if(node.src && node.src.indexOf(srcValue)>-1){
									loaded = true;
									node.onload = null;
									node.onerror = null;
									clearImgTmp();
								}
		
							}
							node.onerror = fail;
		
							node.src = srcValue;
							timeoutList.push($timeout(function(){
		
								if(!loaded && !(node.src && node.src.indexOf(srcValue)>-1 && !node.complete)){
									retry();
								}
							},retryTimeout))
						}
		
		
						scope.$on('$destroy',function(){
							var timeoutItem;
							while(timeoutItem = timeoutList.pop()){
								$timeout.cancel(timeoutItem);
							}
						})
		
						function retry(){
							if(count < retryCount){
		
								count++;
		
								if(!parallel){
		
									attr.$set(name, defaultSrc);
									/*$timeout(function(){
										attr.$set(name, defaultSrc);*/
										$timeout(function(){
											load();
										},0);
								  /*  },0)*/
								}else{
									srcTmp = srcValue;
									console.log('retry count',count,retryCount);
									if(srcTmp.indexOf('?')<0){
										srcTmp+='?'
									}
		
									srcTmp +=('&mmSrcParallelRetry='+Date.now());
									var imgTmp = new Image();
		
		
									imgTmp.onload = function(){
										attr.$set(name,imgTmp.src);
										console.log(imgTmp.src,imgTmp,node.complete)
										//setTimeout(function(){
											clearImgTmp();
									   // },0)
		
		
									}
		
									imgTmp.onerror = fail;
		
		
									imgTmp.src = srcTmp;
		
									timeoutList.push($timeout(function(){
										if(!loaded){
											retry();
										}
									},retryTimeout));
		
									imgTmpList.push(imgTmp);
								}
		
								return true;
		
							}else{
								return false;
		
							}
		
						}
					}
				};
		
			}])
	
	/***/ }),
	/* 332 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('mmPaste', [
				'$timeout',
			   'utilFactory',
			   'stateManageService',
				function($timeout,utilFactory,stateManageService) {
		
		
					function hasFile(clipboardData){
						var items = clipboardData.items;
						var hasFile = false;
						if(clipboardData.items && clipboardData.items.length>=0){
							for(var i = 0 ;i<items.length;i++){
								if(items[i].kind == 'file'){
									hasFile = true;
								}
							}
						}
						return hasFile;
					}
		
					return {
						restrict: 'EA',
						scope:{
							pasteLimit:'=',
							pasteResetTime:'='
						},
						link: function( scope, element, attributes ) {
							var limit = scope.pasteLimit || 1;
							var resetTime = scope.pasteResetTime || 200;
							var currentCount= 0;
							var timer;
							element.on('paste',function(e){
								var originalEvent = e.originalEvent;
								if(!stateManageService.canDo('pasteFile')){
									e.preventDefault();
									e.stopImmediatePropagation();
									return;
								}
		
								if(utilFactory.browser.mozilla){
									if(originalEvent.clipboardData && originalEvent.clipboardData.types.length == 0){
										e.preventDefault();
										e.stopImmediatePropagation();
									}
								}
		
		
		
								if(currentCount>= limit){
									e.preventDefault();
									e.stopImmediatePropagation();
								}else{
									timer && $timeout.cancel(timer);
									timer = $timeout(function(){
										currentCount = 0;
									},resetTime);
									currentCount ++;
								}
							})
						}
					};
				}])
	
	/***/ }),
	/* 333 */
	/***/ (function(module, exports) {
	
		angular.module('Directives')
			.directive('contactPicker', [
				'$timeout',
				'$log',
				'$document',
				'$stateParams',
				'$rootScope',
				'chatFactory',
				'accountFactory',
				'contactFactory',
				'appFactory',
				'confFactory',
				'utilFactory',
				'stateManageService',
				'mmpop',
				function($timeout,$log,$document,$stateParams, $rootScope,chatFactory, accountFactory, contactFactory, appFactory, confFactory, utilFactory,stateManageService,mmpop) {
		
		
		
					function getContactMap(contactList){
						var result = {},item;
						for(var i =0 ; i<contactList.length;i++){
							item = contactList[i];
							result[item.UserName] = item;
						}
						return result;
					}
		
					return {
						restrict: 'EA',
						scope:{
							selectList:'=',
							//contactList:'=',
							pickConfig:'=',
							initList:'='
						},
						templateUrl:'contactPicker.html',
						link: function ($scope, element, attributes) {
		
		
							var selectorContainer ;
		
							$scope.$watch(function(){
								return $scope.selectList.length;
							},function(len){
								if(len > 15){
									if(!selectorContainer) selectorContainer = $('.selector', element)[0];
									setTimeout(function(){
										selectorContainer.scrollTop= 10000;
									},20);
		
								}
							})
		
		
		
							stateManageService.change('contactPicker:active',true);
							$scope.$on('$destroy',function(){
								stateManageService.change('contactPicker:active',false);
							})
		
							var searchTimer ;
		
							var searchList;
							var pickConfig = $scope.pickConfig;
		
							pickConfig.opt['all'] = pickConfig.opt['all'] || {};
							var initList = $scope.initList || [];
							$scope.contactList = getContactList(contactFactory.pickContacts(pickConfig.types,pickConfig.opt,true).result,initList);
							$scope.selectList = $scope.selectList || [];
		
							initCurrent();
							$scope.search = function (e) {
								if(searchTimer){ $timeout.cancel(searchTimer); }
		
								searchTimer = $timeout(function () {
									if(!$scope.keyword){
										$scope.contactList =getContactList(contactFactory.pickContacts(pickConfig.types,pickConfig.opt,true).result,initList);
										initCurrent(true);
		
									}else{
										contactFactory.searchKey = $scope.keyword;
										searchList && searchList.close();
		
										var filterContacts = $.extend(getContactMap($scope.selectList),pickConfig.opt['all'].filterContacts);
										var searchPickConfig = $.extend({},pickConfig.opt,{
											all: $.extend({},pickConfig.opt['all'],{
												noHeader:true,
												keyword: $scope.keyword,
												filterContacts: filterContacts
											})
										})
										$scope.contactList = contactFactory.pickContacts(pickConfig.types, searchPickConfig,true).result;
										initCurrent(true);
									}
		
								},200);
							};
		
							/**
							 * 点击选择或取消选择联系人
							 * @param  {[type]} contact
							 */
							$scope.toggleUser = function (contact) {
								$scope.current =contact;
								var index = _isCheck(contact.UserName);
								if($scope.keyword){
									$scope.keyword = '';
									$scope.current = undefined;
									$scope.search();
								}
		
								if( index == -1 ){
									$scope.selectList.push(contact);
								}else{
									$scope.selectList.splice(index,1);
								}
							}
							/**
							 * 点击删除选择联系人
							 * @param  {[type]} userName
							 */
							$scope.delUser = function (userName) {
								var index = _isCheck(userName);
								if( index > -1 ){
									$scope.selectList.splice(index,1);
								}
							}
		
							function _isCheck (userName) {
								var index = -1;
								angular.forEach($scope.selectList,function (user,i) {
									if(user.UserName == userName){
										index = i;
										return;
									}
								});
								return index;
							}
		
							function getContactList (searchContact,initContact){
								searchContact.unshift.apply(searchContact,initContact);
								return searchContact;
							}
		
							/**
							 * 检测联系人是否在当前选择列表
							 * @param  {[type]}  userName
							 */
							$scope.isCheck = function (userName) {
								return _isCheck(userName) == -1 ? false : true;
							}
		
							$scope.searchKeydown = function (e) {
								switch(e.keyCode){
									case confFactory.KEYCODE_ENTER:
										$scope.current && $scope.toggleUser($scope.current);
		
										e.preventDefault();
										e.stopPropagation();
										$scope.$digest();
										break;
									case confFactory.KEYCODE_BACKSPACE:
										// delLastUser
										if(!$scope.keyword){
											var user = $scope.selectList.pop();
											user && $scope.delUser(user.UserName);
											e.stopPropagation();
											e.preventDefault();
											$scope.$digest();
										}
		
										// ie9 的 input 事件是不支持 backspace 的
										(utilFactory.browser.msie&&utilFactory.browser.version==9) && $scope.search();
										break;
								}
		
							};
							$(document).on('keydown', 'body', $scope.searchKeydown);
		
							$scope.heightCalc = function(item){
								if(item.type === 'header'){
									return 32;
								}else{
									return 62;
								}
							}
		
							$scope.mmRepeatKeyboard.start();
		
					 /*       scope.$watch(function () {
								return scope.allContacts;
							}, function (newValue) {
								if(!scope.current && newValue.length > 0){
									scope.current =scope.allContacts[0];
									scope.mmRepeatKeyboard.setSelectItem(scope.current);
								}
							});
		*/
							function selectItem(item){
								$scope.current =item;
								$scope.mmRepeatKeyboard.setSelectItem(item);
		
							}
		
							function initCurrent(reset){
								if((!$scope.current||reset) && $scope.contactList.length > 0 && $scope.keyword){
									if($scope.contactList[0].type == 'header'){
										selectItem($scope.contactList[1]);
									}else{
										selectItem($scope.contactList[0]);
									}
		
								}
							}
							$scope.mmRepeatKeyboard.setJudgeFun(function(item){
								return item.UserName;
							});
		
							$scope.$on('mmrepeat:select',function(e,item){
								$scope.current = item;
								$scope.$digest();
							});
		
							$scope.$on('$destroy',function(){
								$(document).off('keydown', 'body', $scope.searchKeydown);
							})
		
		
						}
					};
				}])
	
	/***/ }),
	/* 334 */
	/***/ (function(module, exports) {
	
		/**
		 * Created by arminchen on 2015/3/25.
		 * demo: <img class="qrcode" mm-src="{{qrcodeUrl}}"  mm-src-parallel mm-src-timeout="2000" mm-src-retry-count="10" src="images/qrcode.jpg">
		 */
		angular.module('Directives')
			.directive('mmActionTrack', ['actionTrack','utilFactory',function(actionTrack,utilFactory) {
		
				var $window = $(window);
				var height = $window.height();
				var width = $window.width();
				$window.on('resize',function(e){
		
					utilFactory.fitRun('resize',function(){
						var currentHeight = $window.height();
						var currentWidth = $window.width();
						var stateList = [];
						var heightState = 'height-'+(height > currentHeight?'smaller':'bigger');
						var widthState = 'width-'+(width > currentWidth?'smaller':'bigger');
		
						if(height != currentHeight){
							stateList.push(heightState);
						}
		
						if(width != currentWidth){
							stateList.push(widthState);
						}
		
		
						stateList.length > 0 && actionTrack.addRecord({
							action:stateList.join(' '),
							type:'resize'
						});
		
						height = currentHeight;
						width = currentWidth;
					},200,500);
				});
		
				return {
					priority: 99,
					scope:{
						types: '=trackType',
						opt:'=trackOpt'
					},
					link: function(scope, element, attr) {
					   var opt = scope.opt;
					   var types = scope.types;
						for(var key in types){
							var type = types[key];
							if(type=='keydown'){
								var keys = opt.keys;
								var keyMap = {
									enter:13,
									backspace:8,
									blankspace:32
								}
								element.on('keydown',function(e){
									for(var index in keys){
										if(keyMap[keys[index]]== e.keyCode){
											actionTrack.addRecord({
												type:'keydown',
												action:opt.target +'-'+ keys[index]
											})
										}
									}
								})
							}
		
		
		
		
		
							if(type=='click'){
								var prevTimeStamp ;
								element.on('click',function(e){
		
									// 发送文件按钮用了 webuploader 有一次点击触发两次的现象
									if(prevTimeStamp && (e.timeStamp - prevTimeStamp <= 30)){
										return;
									}
		
									prevTimeStamp = e.timeStamp;
									actionTrack.addRecord({
										type:'click',
										action:opt.target
									})
								/*    utilFactory.fitRun('trackClick',function(){
		
									},100,200);*/
		
								})
		
							}
		
		
							if(type=='focus'){
								element.on('focus',function(){
									actionTrack.addRecord({
										type:'focus',
										action:opt.target
									})
								})
							}
						}
		
		
		
		
					}
				};
		
			}]).factory('actionTrack', [
				'reportService',
				function (reportService) {
					var limit = 100;
					var recordList = [];
		
					var service = {
						report:function(){
							recordList.length > 0 && reportService.report(reportService.ReportType.actionRecord,{
							   actions:recordList
							},true);
							recordList = [];
						},
						addRecord:function(actionRecord){
							if(recordList.length > limit){
								return ;
							}
							console.log('record',actionRecord)
							actionRecord.time = Date.now();
							recordList.push(actionRecord);
						}
					};
					return service;
				}]);
	
	/***/ }),
	/* 335 */
	/***/ (function(module, exports) {
	
		angular.module('Directives').directive('mmError', ['$parse', function($parse){
			return {
				restrict: 'A',
				compile: function($element, attr) {
					var fn = $parse(attr['mmError']);
		
					return function(scope, element, attr) {
						element.on('error', function(event) {
							scope.$apply(function() {
								fn(scope, {$event:event});
							});
						});
					};
		
				}
			};
		
		}]);
	
	/***/ }),
	/* 336 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function(window, angular, undefined) {
			'use strict';
		
			angular.module('ngClipboard', []).
				provider('ngClip', function() {
					var self = this;
					this.path = '//cdnjs.cloudflare.com/ajax/libs/zeroclipboard/2.1.6/ZeroClipboard.swf';
					return {
						setPath: function(newPath) {
							self.path = newPath;
						},
						setConfig: function(config) {
							self.config = config;
						},
						$get: function() {
							return {
								path: self.path,
								config: self.config
							};
						}
					};
				}).
				run(['$rootScope','ngClip', function($rootScope,ngClip) {
					var config = {
						swfPath: ngClip.path,
						trustedDomains: ["*"],
						allowScriptAccess: "always",
						forceHandCursor: true,
					};
					function initZeroClipboard(){
						__webpack_require__.e/* nsure */(4, function (require) {
							var ZeroClipboard = __webpack_require__(337);
							ZeroClipboard.config(angular.extend(config, ngClip.config || {}));
						});
					}
					if(window.ZeroClipboard){
						initZeroClipboard();
					}else{
						$rootScope.$on('root:pageInit:success',function(){
							initZeroClipboard();
						});
					}
				}]).
				directive('clipCopy', ['ngClip', function (ngClip) {
					return {
						scope: {
							clipCopy: '&',
							clipClick: '&',
							clipClickFallback: '&'
						},
						restrict: 'A',
						link: function (scope, element, attrs) {
							// Bind a fallback function if flash is unavailable
							__webpack_require__.e/* nsure */(4/* duplicate */, function (require) {
								var ZeroClipboard = __webpack_require__(337);
								if (ZeroClipboard.isFlashUnusable()) {
									element.bind('click', function($event) {
										// Execute the expression with local variables `$event` and `copy`
										scope.$apply(scope.clipClickFallback({
											$event: $event,
											copy: scope.$eval(scope.clipCopy)
										}));
									});
		
									return;
								}
		
								// Create the client object
								var client = new ZeroClipboard(element);
								if (attrs.clipCopy === "") {
									scope.clipCopy = function(scope) {
										return element[0].previousElementSibling.innerText;
									};
								}
								client.on( 'ready', function(readyEvent) {
		
									client.on('copy', function (event) {
										var clipboard = event.clipboardData;
										clipboard.setData(attrs.clipCopyMimeType || 'text/plain', scope.$eval(scope.clipCopy));
									});
		
									client.on( 'aftercopy', function(event) {
										if (angular.isDefined(attrs.clipClick)) {
											scope.$apply(scope.clipClick);
										}
									});
		
									scope.$on('$destroy', function() {
										client.destroy();
									});
								});
							});
						}
					};
				}]);
		})(window, window.angular);
	
	/***/ }),
	/* 337 */,
	/* 338 */
	/***/ (function(module, exports) {
	
		(function () {
		'use strict';
		
		/* Services */
		
		angular.module('Filters')
			.filter('HTMLEnCode', function (text, length, end) {
				// body...
			})
			.filter('HTMLDeCode', function () {
				return function (text, length, end) {
					if (text.length == 0) return "";
					text = text.replace(/&lt;/g, "<")
						.replace(/&gt;/g, ">")
						.replace(/&#39;/g, "\'")
						.replace(/&quot;/g, "\"")
						.replace(/&amp;/g, "&");
		
					return text;
				};
			})
			.filter('VoiceLengthFilter', function () {
				return function (text, length, end) {
					if (text.length == 0) return 0;
		
					return Math.round(text / 1000);
				};
			})
			.filter("emojiHideFilter", function(){
				return function (text, length, end){
					if (!text || text.length == 0) return "";
		
					return text.replace(/<span class=.emoji.*?<\/span>/g, _("809bb9d"));
				}
			})
			.filter("checkurlFilter",["utilFactory", function(utilFactory){
				return function (text, length, end){
					if (!text || text.length == 0) return "";
		
					return utilFactory.genCheckURL(text);
				}
			}])
			.filter("timeFormat",["utilFactory", function(utilFactory){
				var map = [_("562d747"),_("1603b06"),_("b5a6a07"),_("e60725e"),_("170fc8e"),_("eb79cea"),_("2457513")];
				return function (time){
					var time = time*1000;
					var date =new Date();
					var now = date.getTime()/1000;
					var today = date.getDay();
					date.setTime(time);
					var hours = date.getHours();
					var minutes = date.getMinutes();
					var day = date.getDay();
					var years = date.getFullYear()%100;
					var month = date.getMonth() + 1;
					var result;
					var sevenDayAgo = (now - time) > 7 * 24 * 60 * 60;
					var isToday = ((now-time)< 24 * 60 * 60) && (day == today);
		
					if(minutes<10){
						minutes = '0'+minutes;
					}
					if(isToday){
						result = hours+':'+minutes;
					}else if(!sevenDayAgo){
						result = map[day];
					}else{
						result = years + '/' + month +'/'+date.getDate()
					}
		
		
					return result;
				}
			}]);
		})();
	
	/***/ }),
	/* 339 */
	/***/ (function(module, exports) {
	
		(function(){
		'use strict';
		
		/* Services */
		
		angular.module('Filters')
		.filter('emojiFilter',['emojiFactory',function(emojiFactory) {
			return function(text, length, end) {
				if (text.length == 0) return "";
				text = text.replace(/\[([^\]]+)\]/g,function (content,text) {
					return emojiFactory.getEmoticonByText(text);
				});
				return text;
			};
		}]);
		})();
	
	/***/ })
	]);/* vhtml-webpack-plugin version: 0.1.38 */